From 4aa0ace103c8968d4f4aa0dcd1cfa4fe96b22664 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Thu, 14 Jun 2018 16:55:45 -0700 Subject: [PATCH 01/22] Background execution implementation for iOS --- lib/ui/dart_runtime_hooks.cc | 52 ++++++++++- lib/ui/dart_ui.gni | 1 + lib/ui/natives.dart | 4 + lib/ui/plugins.dart | 28 ++++++ lib/ui/ui.dart | 1 + runtime/dart_isolate.cc | 42 +++++++++ runtime/dart_isolate.h | 4 + shell/common/engine.cc | 14 ++- shell/common/run_configuration.cc | 10 +++ shell/common/run_configuration.h | 5 ++ shell/platform/darwin/ios/BUILD.gn | 3 + .../Headers/FlutterHeadlessDartRunner.h | 31 ++++++- .../Source/FlutterAppDelegate_Internal.h | 18 ++++ .../ios/framework/Source/FlutterChannels.mm | 5 ++ .../Source/FlutterHeadlessDartRunner.mm | 89 +++++++++++++++++-- .../darwin/ios/headless_platform_view_ios.h | 38 ++++++++ .../darwin/ios/headless_platform_view_ios.mm | 20 +++++ shell/platform/darwin/ios/platform_view_ios.h | 10 +-- .../platform/darwin/ios/platform_view_ios.mm | 11 +-- 19 files changed, 353 insertions(+), 33 deletions(-) create mode 100644 lib/ui/plugins.dart create mode 100644 shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h create mode 100644 shell/platform/darwin/ios/headless_platform_view_ios.h create mode 100644 shell/platform/darwin/ios/headless_platform_view_ios.mm diff --git a/lib/ui/dart_runtime_hooks.cc b/lib/ui/dart_runtime_hooks.cc index ca129cb4d9768..8937808fab4fa 100644 --- a/lib/ui/dart_runtime_hooks.cc +++ b/lib/ui/dart_runtime_hooks.cc @@ -48,7 +48,10 @@ namespace blink { #define BUILTIN_NATIVE_LIST(V) \ V(Logger_PrintString, 1) \ V(SaveCompilationTrace, 0) \ - V(ScheduleMicrotask, 1) + V(ScheduleMicrotask, 1) \ + V(LookupClosure, 2) \ + V(LookupClosureLibrary, 1) \ + V(GetFunctionName, 1) BUILTIN_NATIVE_LIST(DECLARE_FUNCTION); @@ -223,4 +226,51 @@ void ScheduleMicrotask(Dart_NativeArguments args) { UIDartState::Current()->ScheduleMicrotask(closure); } +void LookupClosure(Dart_NativeArguments args) { + Dart_Handle closure_name = Dart_GetNativeArgument(args, 0); + Dart_Handle library_name = Dart_GetNativeArgument(args, 1); + Dart_Handle library; + if (library_name == Dart_Null()) { + library = Dart_RootLibrary(); + } else { + library = Dart_LookupLibrary(library_name); + DART_CHECK_VALID(library); + } + Dart_Handle closure = Dart_GetClosure(Dart_RootLibrary(), closure_name); + Dart_SetReturnValue(args, closure); +} + +void LookupClosureLibrary(Dart_NativeArguments args) { + Dart_Handle closure = Dart_GetNativeArgument(args, 0); + if (Dart_IsClosure(closure)) { + closure = Dart_ClosureFunction(closure); + DART_CHECK_VALID(closure); + } + Dart_Handle owner = closure; + Dart_Handle url = Dart_Null(); + // TOOD(bkonyi): do we need to do this loop? + do { + owner = Dart_FunctionOwner(owner); + if (Dart_IsLibrary(owner)) { + url = Dart_LibraryUrl(owner); + break; + } + } while (!Dart_IsLibrary(owner)); + Dart_SetReturnValue(args, url); +} + +void GetFunctionName(Dart_NativeArguments args) { + Dart_Handle func = Dart_GetNativeArgument(args, 0); + if (Dart_IsClosure(func)) { + func = Dart_ClosureFunction(func); + DART_CHECK_VALID(func); + } + Dart_Handle result = Dart_FunctionName(func); + if (Dart_IsError(result)) { + Dart_PropagateError(result); + return; + } + Dart_SetReturnValue(args, result); +} + } // namespace blink diff --git a/lib/ui/dart_ui.gni b/lib/ui/dart_ui.gni index e1885d1d09ace..e9a315ac3694e 100644 --- a/lib/ui/dart_ui.gni +++ b/lib/ui/dart_ui.gni @@ -11,6 +11,7 @@ dart_ui_files = [ "$flutter_root/lib/ui/lerp.dart", "$flutter_root/lib/ui/natives.dart", "$flutter_root/lib/ui/painting.dart", + "$flutter_root/lib/ui/plugins.dart", "$flutter_root/lib/ui/pointer.dart", "$flutter_root/lib/ui/semantics.dart", "$flutter_root/lib/ui/text.dart", diff --git a/lib/ui/natives.dart b/lib/ui/natives.dart index 4dfb2e481675e..256e9102038e3 100644 --- a/lib/ui/natives.dart +++ b/lib/ui/natives.dart @@ -48,6 +48,10 @@ dynamic _saveCompilationTrace() native 'SaveCompilationTrace'; void _scheduleMicrotask(void callback()) native 'ScheduleMicrotask'; +dynamic _lookupClosure(String name, String libraryPath) native 'LookupClosure'; +dynamic _lookupClosureLibrary(Function closure) native 'LookupClosureLibrary'; +String _getFunctionName(Function func) native 'GetFunctionName'; + // Required for gen_snapshot to work correctly. int _isolateId; diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart new file mode 100644 index 0000000000000..e3078a54964a1 --- /dev/null +++ b/lib/ui/plugins.dart @@ -0,0 +1,28 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +part of dart.ui; + +abstract class PluginUtilities { + static Function getClosureByName({String name, Uri libraryUri}) { + if (name == null) { + throw new ArgumentError("'name' must be provided."); + } + return _lookupClosure(name, libraryUri?.toString()); + } + + static String getPathForFunctionLibrary(Function closure) { + if (closure == null) { + throw new ArgumentError("'closure' cannot be null."); + } + return _lookupClosureLibrary(closure); + } + + static String getNameOfFunction(Function closure) { + if (closure == null) { + throw new ArgumentError("'closure' cannot be null."); + } + return _getFunctionName(closure); + } +} diff --git a/lib/ui/ui.dart b/lib/ui/ui.dart index 1d9782311f310..8c4480c072cdb 100644 --- a/lib/ui/ui.dart +++ b/lib/ui/ui.dart @@ -30,6 +30,7 @@ part 'isolate_name_server.dart'; part 'lerp.dart'; part 'natives.dart'; part 'painting.dart'; +part 'plugins.dart'; part 'pointer.dart'; part 'semantics.dart'; part 'text.dart'; diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc index 66af59a5872c7..b15bc68ed96f5 100644 --- a/runtime/dart_isolate.cc +++ b/runtime/dart_isolate.cc @@ -482,6 +482,48 @@ bool DartIsolate::Run(const std::string& entrypoint_name) { return true; } +FXL_WARN_UNUSED_RESULT +bool DartIsolate::RunFromLibrary(const std::string& library_name, + const std::string& entrypoint_name) { + TRACE_EVENT0("flutter", "DartIsolate::RunFromLibrary"); + if (phase_ != Phase::Ready) { + return false; + } + + tonic::DartState::Scope scope(this); + + Dart_Handle library = Dart_LookupLibrary(tonic::ToDart(library_name.c_str())); + if (tonic::LogIfError(library)) { + return false; + } + + Dart_Handle entrypoint = + Dart_GetClosure(library, tonic::ToDart(entrypoint_name.c_str())); + if (tonic::LogIfError(entrypoint)) { + return false; + } + + Dart_Handle isolate_lib = Dart_LookupLibrary(tonic::ToDart("dart:isolate")); + if (tonic::LogIfError(isolate_lib)) { + return false; + } + + Dart_Handle isolate_args[] = { + entrypoint, + Dart_Null(), + }; + + if (tonic::LogIfError(Dart_Invoke( + isolate_lib, tonic::ToDart("_startMainIsolate"), + sizeof(isolate_args) / sizeof(isolate_args[0]), isolate_args))) { + return false; + } + + phase_ = Phase::Running; + FXL_DLOG(INFO) << "New isolate is in the running state."; + return true; +} + bool DartIsolate::Shutdown() { TRACE_EVENT0("flutter", "DartIsolate::Shutdown"); // This call may be re-entrant since Dart_ShutdownIsolate can invoke the diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h index ceed7a0fd7a2a..530e2c0402a71 100644 --- a/runtime/dart_isolate.h +++ b/runtime/dart_isolate.h @@ -79,6 +79,10 @@ class DartIsolate : public UIDartState { FXL_WARN_UNUSED_RESULT bool Run(const std::string& entrypoint); + FXL_WARN_UNUSED_RESULT + bool RunFromLibrary(const std::string& library_name, + const std::string& entrypoint); + FXL_WARN_UNUSED_RESULT bool Shutdown(); diff --git a/shell/common/engine.cc b/shell/common/engine.cc index de3fd23489953..6c168ec7ef615 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -152,9 +152,17 @@ bool Engine::PrepareAndLaunchIsolate(RunConfiguration configuration) { return false; } - if (!isolate->Run(configuration.GetEntrypoint())) { - FXL_LOG(ERROR) << "Could not run the isolate."; - return false; + if (configuration.GetEntrypointLibrary().empty()) { + if (!isolate->Run(configuration.GetEntrypoint())) { + FXL_LOG(ERROR) << "Could not run the isolate."; + return false; + } + } else { + if (!isolate->RunFromLibrary(configuration.GetEntrypointLibrary(), + configuration.GetEntrypoint())) { + FXL_LOG(ERROR) << "Could not run the isolate."; + return false; + } } return true; diff --git a/shell/common/run_configuration.cc b/shell/common/run_configuration.cc index eb315f25e8280..1fba1da6b9d6d 100644 --- a/shell/common/run_configuration.cc +++ b/shell/common/run_configuration.cc @@ -60,6 +60,12 @@ void RunConfiguration::SetEntrypoint(std::string entrypoint) { entrypoint_ = std::move(entrypoint); } +void RunConfiguration::SetEntrypointAndLibrary(std::string entrypoint, + std::string library) { + SetEntrypoint(entrypoint); + entrypoint_library_ = std::move(library); +} + fml::RefPtr RunConfiguration::GetAssetManager() const { return asset_manager_; } @@ -68,6 +74,10 @@ const std::string& RunConfiguration::GetEntrypoint() const { return entrypoint_; } +const std::string& RunConfiguration::GetEntrypointLibrary() const { + return entrypoint_library_; +} + std::unique_ptr RunConfiguration::TakeIsolateConfiguration() { return std::move(isolate_configuration_); diff --git a/shell/common/run_configuration.h b/shell/common/run_configuration.h index 5d45d2a26bc09..b0adf9181fa6d 100644 --- a/shell/common/run_configuration.h +++ b/shell/common/run_configuration.h @@ -37,16 +37,21 @@ class RunConfiguration { void SetEntrypoint(std::string entrypoint); + void SetEntrypointAndLibrary(std::string entrypoint, std::string library); + fml::RefPtr GetAssetManager() const; const std::string& GetEntrypoint() const; + const std::string& GetEntrypointLibrary() const; + std::unique_ptr TakeIsolateConfiguration(); private: std::unique_ptr isolate_configuration_; fml::RefPtr asset_manager_; std::string entrypoint_ = "main"; + std::string entrypoint_library_ = ""; FXL_DISALLOW_COPY_AND_ASSIGN(RunConfiguration); }; diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index d9450d64d65f4..6beb227ed0c4a 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -43,6 +43,7 @@ shared_library("create_flutter_framework_dylib") { sources = [ "framework/Source/FlutterAppDelegate.mm", + "framework/Source/FlutterAppDelegate_Internal.h", "framework/Source/FlutterChannels.mm", "framework/Source/FlutterCodecs.mm", "framework/Source/FlutterDartProject.mm", @@ -73,6 +74,8 @@ shared_library("create_flutter_framework_dylib") { "framework/Source/platform_message_router.mm", "framework/Source/vsync_waiter_ios.h", "framework/Source/vsync_waiter_ios.mm", + "headless_platform_view_ios.h", + "headless_platform_view_ios.mm", "ios_external_texture_gl.h", "ios_external_texture_gl.mm", "ios_gl_context.h", diff --git a/shell/platform/darwin/ios/framework/Headers/FlutterHeadlessDartRunner.h b/shell/platform/darwin/ios/framework/Headers/FlutterHeadlessDartRunner.h index 522766e410355..646a5164c43d9 100644 --- a/shell/platform/darwin/ios/framework/Headers/FlutterHeadlessDartRunner.h +++ b/shell/platform/darwin/ios/framework/Headers/FlutterHeadlessDartRunner.h @@ -7,28 +7,51 @@ #import +#include "FlutterBinaryMessenger.h" #include "FlutterDartProject.h" #include "FlutterMacros.h" +/** +A callback for when FlutterHeadlessDartRunner has attempted to start a Dart +Isolate in the background. + +- Parameter success: YES if the Isolate was started and run successfully, NO + otherwise. +*/ +typedef void (^FlutterHeadlessDartRunnerCallback)(BOOL success); + /** The FlutterHeadlessDartRunner runs Flutter Dart code with a null rasterizer, and no native drawing surface. It is appropriate for use in running Dart code e.g. in the background from a plugin. */ FLUTTER_EXPORT -@interface FlutterHeadlessDartRunner : NSObject +@interface FlutterHeadlessDartRunner : NSObject /** Runs a Dart function on an Isolate that is not the main application's Isolate. - The first call will create a new Isolate. Subsequent calls will reuse that - Isolate. The Isolate is destroyed when the FlutterHeadlessDartRunner is - destroyed. + The first call will create a new Isolate. Subsequent calls will return + immediately. - Parameter entrypoint: The name of a top-level function from the same Dart library that contains the app's main() function. */ - (void)runWithEntrypoint:(NSString*)entrypoint; +/** + Runs a Dart function on an Isolate that is not the main application's Isolate. + The first call will create a new Isolate. Subsequent calls will return + immediately. + + - Parameter entrypoint: The name of a top-level function from a Dart library. + - Parameter uri: The URI of the Dart library which contains entrypoint. + - Parameter callback: The callback to be invoked when the new Isolate is + invoked. +*/ +- (void)runWithEntrypointAndCallback:(NSString*)entrypoint + libraryUri:(NSString*)uri + completion:(FlutterHeadlessDartRunnerCallback)callback; + @end #endif // FLUTTER_FLUTTERHEADLESSDARTRUNNER_H_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h new file mode 100644 index 0000000000000..c01a33d6f3266 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h @@ -0,0 +1,18 @@ +// Copyright 2018 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/ios/framework/Headers/FlutterAppDelegate.h" + +@interface FlutterAppDelegate () + +@property(readonly, nonatomic) NSMutableArray* pluginDelegates; +@property(readonly, nonatomic) NSMutableDictionary* pluginPublications; + +@end + +@interface FlutterAppDelegateRegistrar : NSObject + +- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(FlutterAppDelegate*)delegate; + +@end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterChannels.mm b/shell/platform/darwin/ios/framework/Source/FlutterChannels.mm index c9a75b0f49c67..f783a021be42e 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterChannels.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterChannels.mm @@ -166,6 +166,11 @@ + (instancetype)methodChannelWithName:(NSString*)name autorelease]; } +- (void)setBinaryMessenger:(NSObject*)messenger { + [_messenger release]; + _messenger = [messenger retain]; +} + - (instancetype)initWithName:(NSString*)name binaryMessenger:(NSObject*)messenger codec:(NSObject*)codec { diff --git a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm index add5a78dc4a4c..ce2401b931b3b 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm @@ -8,6 +8,7 @@ #include #include +#include #include "flutter/fml/message_loop.h" #include "flutter/shell/common/engine.h" @@ -17,29 +18,54 @@ #include "flutter/shell/common/switches.h" #include "flutter/shell/common/thread_host.h" #include "flutter/shell/platform/darwin/common/command_line.h" +#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h" +#include "flutter/shell/platform/darwin/ios/headless_platform_view_ios.h" +#include "flutter/shell/platform/darwin/ios/platform_view_ios.h" #include "lib/fxl/functional/make_copyable.h" -static std::unique_ptr CreateHeadlessPlatformView(shell::Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); +static std::unique_ptr CreateHeadlessPlatformView( + shell::Shell& shell) { + return std::make_unique(shell, shell.GetTaskRunners()); } static std::unique_ptr CreateHeadlessRasterizer(shell::Shell& shell) { return std::make_unique(shell.GetTaskRunners()); } +static std::string CreateShellLabel() { + static size_t count = 1; + std::stringstream stream; + stream << "io.flutter.headless."; + stream << count++; + return stream.str(); +} + @implementation FlutterHeadlessDartRunner { shell::ThreadHost _threadHost; std::unique_ptr _shell; + shell::PlatformMessageRouter _message_router; } -- (void)runWithEntrypoint:(NSString*)entrypoint { +- (instancetype)init { + self = [super init]; + return self; +} + +- (void)dealloc { + [super dealloc]; +} + +- (void)runWithEntrypointAndCallback:(NSString*)entrypoint + libraryUri:(NSString*)uri + completion:(FlutterHeadlessDartRunnerCallback)callback { if (_shell != nullptr || entrypoint.length == 0) { FXL_LOG(ERROR) << "This headless dart runner was already used to run some code."; return; } - const auto label = "io.flutter.headless"; + const auto label = CreateShellLabel(); // Create the threads to run the shell on. _threadHost = { @@ -59,6 +85,10 @@ - (void)runWithEntrypoint:(NSString*)entrypoint { auto settings = shell::SettingsFromCommandLine(shell::CommandLineFromNSProcessInfo()); + // These values set the name of the isolate for debugging. + settings.advisory_script_entrypoint = entrypoint.UTF8String; + settings.advisory_script_uri = uri.UTF8String; + // Create the shell. This is a blocking operation. _shell = shell::Shell::Create( std::move(task_runners), // task runners @@ -77,16 +107,61 @@ - (void)runWithEntrypoint:(NSString*)entrypoint { [[[FlutterDartProject alloc] initFromDefaultSourceForConfiguration] autorelease]; auto config = project.runConfiguration; - - config.SetEntrypoint(entrypoint.UTF8String); + config.SetEntrypointAndLibrary(entrypoint.UTF8String, uri.UTF8String); // Override the default run configuration with the specified entrypoint. _shell->GetTaskRunners().GetUITaskRunner()->PostTask( - fxl::MakeCopyable([engine = _shell->GetEngine(), config = std::move(config)]() mutable { + fxl::MakeCopyable([engine = _shell->GetEngine(), config = std::move(config), + callback = Block_copy(callback)]() mutable { + BOOL success = NO; + FXL_LOG(INFO) << "Attempting to launch background engine configuration..."; if (!engine || !engine->Run(std::move(config))) { FXL_LOG(ERROR) << "Could not launch engine with configuration."; + } else { + FXL_LOG(INFO) << "Background Isolate successfully started and run."; + success = YES; + } + if (callback != nil) { + callback(success); + Block_release(callback); } })); } +- (void)runWithEntrypoint:(NSString*)entrypoint { + [self runWithEntrypointAndCallback:entrypoint libraryUri:nil completion:nil]; +} + +#pragma mark - FlutterBinaryMessenger + +- (void)sendOnChannel:(NSString*)channel message:(NSData*)message { + [self sendOnChannel:channel message:message binaryReply:nil]; +} + +- (void)sendOnChannel:(NSString*)channel + message:(NSData*)message + binaryReply:(FlutterBinaryReply)callback { + NSAssert(channel, @"The channel must not be null"); + fxl::RefPtr response = + (callback == nil) ? nullptr + : fxl::MakeRefCounted( + ^(NSData* reply) { + callback(reply); + }, + _shell->GetTaskRunners().GetPlatformTaskRunner()); + fxl::RefPtr platformMessage = + (message == nil) ? fxl::MakeRefCounted(channel.UTF8String, response) + : fxl::MakeRefCounted( + channel.UTF8String, shell::GetVectorFromNSData(message), response); + + _shell->GetPlatformView()->DispatchPlatformMessage(platformMessage); +} + +- (void)setMessageHandlerOnChannel:(NSString*)channel + binaryMessageHandler:(FlutterBinaryMessageHandler)handler { + reinterpret_cast(_shell->GetPlatformView().get()) + ->GetPlatformMessageRouter() + .SetMessageHandler(channel.UTF8String, handler); +} + @end diff --git a/shell/platform/darwin/ios/headless_platform_view_ios.h b/shell/platform/darwin/ios/headless_platform_view_ios.h new file mode 100644 index 0000000000000..4b93080956cc0 --- /dev/null +++ b/shell/platform/darwin/ios/headless_platform_view_ios.h @@ -0,0 +1,38 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SHELL_PLATFORM_IOS_HEADLESS_PLATFORM_VIEW_IOS_H_ +#define SHELL_PLATFORM_IOS_HEADLESS_PLATFORM_VIEW_IOS_H_ + +#include + +#include "flutter/fml/memory/weak_ptr.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h" +#include "lib/fxl/functional/closure.h" +#include "lib/fxl/macros.h" + +namespace shell { + +class HeadlessPlatformViewIOS : public PlatformView { + public: + explicit HeadlessPlatformViewIOS(Delegate& delegate, + blink::TaskRunners task_runners); + virtual ~HeadlessPlatformViewIOS(); + + PlatformMessageRouter& GetPlatformMessageRouter(); + + private: + PlatformMessageRouter platform_message_router_; + + // |shell::PlatformView| + void HandlePlatformMessage(fxl::RefPtr message); + + FXL_DISALLOW_COPY_AND_ASSIGN(HeadlessPlatformViewIOS); +}; + +} // namespace shell + +#endif // SHELL_PLATFORM_IOS_HEADLESS_PLATFORM_VIEW_IOS_H_ \ No newline at end of file diff --git a/shell/platform/darwin/ios/headless_platform_view_ios.mm b/shell/platform/darwin/ios/headless_platform_view_ios.mm new file mode 100644 index 0000000000000..87ee75891a1e6 --- /dev/null +++ b/shell/platform/darwin/ios/headless_platform_view_ios.mm @@ -0,0 +1,20 @@ + +#include "flutter/shell/platform/darwin/ios/headless_platform_view_ios.h" + +namespace shell { + +HeadlessPlatformViewIOS::HeadlessPlatformViewIOS(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners) + : PlatformView(delegate, std::move(task_runners)) {} + +HeadlessPlatformViewIOS::~HeadlessPlatformViewIOS() = default; + +PlatformMessageRouter& HeadlessPlatformViewIOS::GetPlatformMessageRouter() { + return platform_message_router_; +} + +// |shell::PlatformView| +void HeadlessPlatformViewIOS::HandlePlatformMessage(fxl::RefPtr message) { + platform_message_router_.HandlePlatformMessage(std::move(message)); +} +} \ No newline at end of file diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index e7849dda44641..03c966a44adf8 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -14,14 +14,14 @@ #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h" +#include "flutter/shell/platform/darwin/ios/headless_platform_view_ios.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" #include "lib/fxl/functional/closure.h" #include "lib/fxl/macros.h" namespace shell { -class PlatformViewIOS final : public PlatformView { +class PlatformViewIOS final : public HeadlessPlatformViewIOS { public: explicit PlatformViewIOS(PlatformView::Delegate& delegate, blink::TaskRunners task_runners, @@ -30,8 +30,6 @@ class PlatformViewIOS final : public PlatformView { ~PlatformViewIOS() override; - PlatformMessageRouter& GetPlatformMessageRouter(); - FlutterViewController* GetOwnerViewController() const; void RegisterExternalTexture(int64_t id, NSObject* texture); @@ -59,10 +57,6 @@ class PlatformViewIOS final : public PlatformView { // |shell::PlatformView| void SetSemanticsEnabled(bool enabled) override; - // |shell::PlatformView| - void HandlePlatformMessage( - fxl::RefPtr message) override; - // |shell::PlatformView| void UpdateSemantics(blink::SemanticsNodeUpdates update) override; diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index 1fba8e5e026e5..b1cb9e60459e2 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -21,7 +21,7 @@ blink::TaskRunners task_runners, FlutterViewController* owner_controller, FlutterView* owner_view) - : PlatformView(delegate, std::move(task_runners)), + : HeadlessPlatformViewIOS(delegate, std::move(task_runners)), owner_controller_(owner_controller), owner_view_(owner_view), ios_surface_(owner_view_.createSurface) { @@ -36,10 +36,6 @@ return owner_controller_; } -PlatformMessageRouter& PlatformViewIOS::GetPlatformMessageRouter() { - return platform_message_router_; -} - void PlatformViewIOS::RegisterExternalTexture(int64_t texture_id, NSObject* texture) { RegisterTexture(std::make_shared(texture_id, texture)); @@ -78,11 +74,6 @@ } } -// |shell::PlatformView| -void PlatformViewIOS::HandlePlatformMessage(fxl::RefPtr message) { - platform_message_router_.HandlePlatformMessage(std::move(message)); -} - // |shell::PlatformView| std::unique_ptr PlatformViewIOS::CreateVSyncWaiter() { return std::make_unique(task_runners_); From 59f4c05ec1c2e7dd74859a0286815dad11c263d2 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Thu, 14 Jun 2018 17:18:57 -0700 Subject: [PATCH 02/22] Updated licenses + removed extra line of code --- .../darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm | 1 - travis/licenses_golden/licenses_flutter | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm index ce2401b931b3b..b7cf9fec32d22 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm @@ -45,7 +45,6 @@ @implementation FlutterHeadlessDartRunner { shell::ThreadHost _threadHost; std::unique_ptr _shell; - shell::PlatformMessageRouter _message_router; } - (instancetype)init { diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index 752670eae6e0c..b56c740bdbf55 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -206,6 +206,7 @@ FILE: ../../../flutter/shell/platform/darwin/desktop/Info.plist FILE: ../../../flutter/shell/platform/darwin/ios/framework/Flutter.podspec FILE: ../../../flutter/shell/platform/darwin/ios/framework/Info.plist FILE: ../../../flutter/shell/platform/darwin/ios/framework/module.modulemap +FILE: ../../../flutter/shell/platform/darwin/ios/headless_platform_view_ios.mm FILE: ../../../flutter/shell/platform/embedder/assets/EmbedderInfo.plist FILE: ../../../flutter/shell/platform/embedder/assets/embedder.modulemap FILE: ../../../flutter/shell/platform/embedder/fixtures/simple_main.dart @@ -489,6 +490,7 @@ FILE: ../../../flutter/flutter_kernel_transformers/lib/track_widget_constructor_ FILE: ../../../flutter/lib/ui/isolate_name_server.dart FILE: ../../../flutter/lib/ui/painting/image_encoding.cc FILE: ../../../flutter/lib/ui/painting/image_encoding.h +FILE: ../../../flutter/lib/ui/plugins.dart FILE: ../../../flutter/lib/ui/text/asset_manager_font_provider.cc FILE: ../../../flutter/lib/ui/text/asset_manager_font_provider.h FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h @@ -496,6 +498,7 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlugin FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm +FILE: ../../../flutter/shell/platform/darwin/ios/headless_platform_view_ios.h ---------------------------------------------------------------------------------------------------- Copyright 2018 The Chromium Authors. All rights reserved. @@ -589,6 +592,7 @@ FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc FILE: ../../../flutter/shell/platform/android/android_shell_holder.h FILE: ../../../flutter/shell/platform/android/platform_message_response_android.cc FILE: ../../../flutter/shell/platform/android/platform_message_response_android.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate_Internal.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm ---------------------------------------------------------------------------------------------------- From 2f3e0d89a3a84b99d042fa3acf4eb198c49586a0 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 20 Jun 2018 11:02:24 -0700 Subject: [PATCH 03/22] Addressed some comments --- lib/ui/dart_runtime_hooks.cc | 105 +++++++++++++++--- lib/ui/natives.dart | 5 +- lib/ui/plugins.dart | 25 +++-- .../Source/FlutterHeadlessDartRunner.mm | 9 -- 4 files changed, 106 insertions(+), 38 deletions(-) diff --git a/lib/ui/dart_runtime_hooks.cc b/lib/ui/dart_runtime_hooks.cc index 8937808fab4fa..9da3ff59fcf7e 100644 --- a/lib/ui/dart_runtime_hooks.cc +++ b/lib/ui/dart_runtime_hooks.cc @@ -49,8 +49,9 @@ namespace blink { V(Logger_PrintString, 1) \ V(SaveCompilationTrace, 0) \ V(ScheduleMicrotask, 1) \ - V(LookupClosure, 2) \ - V(LookupClosureLibrary, 1) \ + V(LookupClosure, 3) \ + V(GetFunctionClassName, 1) \ + V(GetFunctionLibraryUrl, 1) \ V(GetFunctionName, 1) BUILTIN_NATIVE_LIST(DECLARE_FUNCTION); @@ -59,7 +60,7 @@ void DartRuntimeHooks::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({BUILTIN_NATIVE_LIST(REGISTER_FUNCTION)}); } -static Dart_Handle GetClosure(Dart_Handle builtin_library, const char* name) { +static Dart_Handle GetFunction(Dart_Handle builtin_library, const char* name) { Dart_Handle getter_name = ToDart(name); Dart_Handle closure = Dart_Invoke(builtin_library, getter_name, 0, nullptr); DART_CHECK_VALID(closure); @@ -67,7 +68,7 @@ static Dart_Handle GetClosure(Dart_Handle builtin_library, const char* name) { } static void InitDartInternal(Dart_Handle builtin_library, bool is_ui_isolate) { - Dart_Handle print = GetClosure(builtin_library, "_getPrintClosure"); + Dart_Handle print = GetFunction(builtin_library, "_getPrintClosure"); Dart_Handle internal_library = Dart_LookupLibrary(ToDart("dart:_internal")); @@ -104,7 +105,7 @@ static void InitDartAsync(Dart_Handle builtin_library, bool is_ui_isolate) { Dart_Handle schedule_microtask; if (is_ui_isolate) { schedule_microtask = - GetClosure(builtin_library, "_getScheduleMicrotaskClosure"); + GetFunction(builtin_library, "_getScheduleMicrotaskClosure"); } else { Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate")); Dart_Handle method_name = @@ -128,7 +129,8 @@ static void InitDartIO(Dart_Handle builtin_library, DART_CHECK_VALID(Dart_SetField(platform_type, ToDart("_nativeScript"), ToDart(script_uri))); } - Dart_Handle locale_closure = GetClosure(builtin_library, "_getLocaleClosure"); + Dart_Handle locale_closure = + GetFunction(builtin_library, "_getLocaleClosure"); DART_CHECK_VALID( Dart_SetField(platform_type, ToDart("_localeClosure"), locale_closure)); } @@ -229,42 +231,109 @@ void ScheduleMicrotask(Dart_NativeArguments args) { void LookupClosure(Dart_NativeArguments args) { Dart_Handle closure_name = Dart_GetNativeArgument(args, 0); Dart_Handle library_name = Dart_GetNativeArgument(args, 1); + Dart_Handle class_name = Dart_GetNativeArgument(args, 2); + DART_CHECK_VALID(closure_name); + DART_CHECK_VALID(library_name); + DART_CHECK_VALID(class_name); + Dart_Handle library; if (library_name == Dart_Null()) { library = Dart_RootLibrary(); } else { library = Dart_LookupLibrary(library_name); - DART_CHECK_VALID(library); } - Dart_Handle closure = Dart_GetClosure(Dart_RootLibrary(), closure_name); + DART_CHECK_VALID(library); + + Dart_Handle closure; + if (Dart_IsNull(class_name)) { + closure = Dart_GetClosure(library, closure_name); + } else { + Dart_Handle cls = Dart_GetClass(library, class_name); + DART_CHECK_VALID(cls); + if (Dart_IsNull(cls)) { + closure = Dart_Null(); + } else { + closure = Dart_GetStaticMethodClosure(library, cls, closure_name); + } + } + DART_CHECK_VALID(closure); + Dart_SetReturnValue(args, closure); } -void LookupClosureLibrary(Dart_NativeArguments args) { +void GetFunctionLibraryUrl(Dart_NativeArguments args) { Dart_Handle closure = Dart_GetNativeArgument(args, 0); if (Dart_IsClosure(closure)) { closure = Dart_ClosureFunction(closure); DART_CHECK_VALID(closure); } - Dart_Handle owner = closure; + + if (!Dart_IsFunction(closure)) { + Dart_SetReturnValue(args, Dart_Null()); + return; + } + Dart_Handle url = Dart_Null(); - // TOOD(bkonyi): do we need to do this loop? - do { - owner = Dart_FunctionOwner(owner); - if (Dart_IsLibrary(owner)) { - url = Dart_LibraryUrl(owner); - break; - } - } while (!Dart_IsLibrary(owner)); + Dart_Handle owner = Dart_FunctionOwner(closure); + if (Dart_IsInstance(owner)) { + owner = Dart_ClassLibrary(owner); + } + if (Dart_IsLibrary(owner)) { + url = Dart_LibraryUrl(owner); + DART_CHECK_VALID(url); + } Dart_SetReturnValue(args, url); } +void GetFunctionClassName(Dart_NativeArguments args) { + Dart_Handle closure = Dart_GetNativeArgument(args, 0); + Dart_Handle result; + + if (Dart_IsClosure(closure)) { + closure = Dart_ClosureFunction(closure); + DART_CHECK_VALID(closure); + } + + if (!Dart_IsFunction(closure)) { + Dart_SetReturnValue(args, Dart_Null()); + return; + } + + bool is_static = false; + result = Dart_FunctionIsStatic(closure, &is_static); + DART_CHECK_VALID(result); + if (!is_static) { + Dart_SetReturnValue(args, Dart_Null()); + return; + } + + result = Dart_FunctionOwner(closure); + DART_CHECK_VALID(result); + + if (Dart_IsLibrary(result) || !Dart_IsInstance(result)) { + Dart_SetReturnValue(args, Dart_Null()); + return; + } + + result = Dart_ClassName(result); + DART_CHECK_VALID(result); + Dart_SetReturnValue(args, result); +} + void GetFunctionName(Dart_NativeArguments args) { Dart_Handle func = Dart_GetNativeArgument(args, 0); + DART_CHECK_VALID(func); + if (Dart_IsClosure(func)) { func = Dart_ClosureFunction(func); DART_CHECK_VALID(func); } + + if (!Dart_IsFunction(func)) { + Dart_SetReturnValue(args, Dart_Null()); + return; + } + Dart_Handle result = Dart_FunctionName(func); if (Dart_IsError(result)) { Dart_PropagateError(result); diff --git a/lib/ui/natives.dart b/lib/ui/natives.dart index 256e9102038e3..ab27a7edbce5b 100644 --- a/lib/ui/natives.dart +++ b/lib/ui/natives.dart @@ -48,8 +48,9 @@ dynamic _saveCompilationTrace() native 'SaveCompilationTrace'; void _scheduleMicrotask(void callback()) native 'ScheduleMicrotask'; -dynamic _lookupClosure(String name, String libraryPath) native 'LookupClosure'; -dynamic _lookupClosureLibrary(Function closure) native 'LookupClosureLibrary'; +Function _lookupClosure(String name, String libraryPath, String className) native 'LookupClosure'; +String _getNameOfFunctionClass(Function closure) native 'GetFunctionClassName'; +String _getFunctionLibraryUrl(Function closure) native 'GetFunctionLibraryUrl'; String _getFunctionName(Function func) native 'GetFunctionName'; // Required for gen_snapshot to work correctly. diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index e3078a54964a1..8c2ffac9150ba 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -5,24 +5,31 @@ part of dart.ui; abstract class PluginUtilities { - static Function getClosureByName({String name, Uri libraryUri}) { + static Function getClosureByName({String name, Uri libraryUri, String className}) { if (name == null) { - throw new ArgumentError("'name' must be provided."); + throw new ArgumentError.notNull('name'); } - return _lookupClosure(name, libraryUri?.toString()); + return _lookupClosure(name, libraryUri?.toString(), className); } static String getPathForFunctionLibrary(Function closure) { if (closure == null) { - throw new ArgumentError("'closure' cannot be null."); + throw new ArgumentError.notNull('closure'); } - return _lookupClosureLibrary(closure); + return _getFunctionLibraryUrl(closure); } static String getNameOfFunction(Function closure) { - if (closure == null) { - throw new ArgumentError("'closure' cannot be null."); - } - return _getFunctionName(closure); + if (closure == null) { + throw new ArgumentError.notNull('closure'); + } + return _getFunctionName(closure); + } + + static String getNameOfFunctionClass(Function closure) { + if(closure == null) { + throw new ArgumentError.notNull('closure'); + } + return _getNameOfFunctionClass(closure); } } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm index b7cf9fec32d22..0a422e2f77b06 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm @@ -47,15 +47,6 @@ @implementation FlutterHeadlessDartRunner { std::unique_ptr _shell; } -- (instancetype)init { - self = [super init]; - return self; -} - -- (void)dealloc { - [super dealloc]; -} - - (void)runWithEntrypointAndCallback:(NSString*)entrypoint libraryUri:(NSString*)uri completion:(FlutterHeadlessDartRunnerCallback)callback { From ddbd5f38f28a1d50d1376d9b927e3d38bdc5469e Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 20 Jun 2018 13:34:39 -0700 Subject: [PATCH 04/22] Added tests for PluginUtilities and updated function params. --- lib/ui/plugins.dart | 37 +++++++++- testing/dart/plugin_utilities_test.dart | 90 +++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 testing/dart/plugin_utilities_test.dart diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index 8c2ffac9150ba..34c919ec5581f 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -4,14 +4,39 @@ part of dart.ui; +/// Functionality for Flutter plugin authors. abstract class PluginUtilities { - static Function getClosureByName({String name, Uri libraryUri, String className}) { + /// Get a closure instance for a specific static or top-level function given + /// a name. + /// + /// `name` is the name of the function we want a closure for. This is a + /// required parameter. + /// + /// `libraryPat h` is the path which points to the library which contains the + /// function of interest. This path can be retrieved using + /// [PluginUtilities.getPathForFunctionLibrary]. If not specified, the root + /// library will be used for the function lookup. + /// + /// `className` is the name of the class in which function `name` is defined. + /// This parameter is required for retrieving closures for static methods. If + /// not provided, `name` is assumed to be referring to a top-level function. + /// + /// Returns a closure for `name` as a [Function] if the lookup was successful. + /// Otherwise, `null` is returned on error. + static Function getClosureByName({String name, String libraryPath, String className}) { if (name == null) { throw new ArgumentError.notNull('name'); } - return _lookupClosure(name, libraryUri?.toString(), className); + return _lookupClosure(name, libraryPath, className); } + /// Get the path for the library which contains a given method. + /// + /// `closure` is the closure of the function that we want to find the library + /// path for. + /// + /// Returns a [String] representing the path to the library which contains + /// `closure`. Returns `null` if an error occurs or `closure` is not found static String getPathForFunctionLibrary(Function closure) { if (closure == null) { throw new ArgumentError.notNull('closure'); @@ -19,6 +44,10 @@ abstract class PluginUtilities { return _getFunctionLibraryUrl(closure); } + /// Get the name of a [Function] as a [String]. + /// + /// Returns a [String] representing the name of the function if the function + /// exists, otherwise `null` is returned. static String getNameOfFunction(Function closure) { if (closure == null) { throw new ArgumentError.notNull('closure'); @@ -26,6 +55,10 @@ abstract class PluginUtilities { return _getFunctionName(closure); } + /// Get the name of a class containing [Function] as a [String]. + /// + /// Returns a [String] representing the name of the function if the function + /// exists and is a member of a class, otherwise `null` is returned. static String getNameOfFunctionClass(Function closure) { if(closure == null) { throw new ArgumentError.notNull('closure'); diff --git a/testing/dart/plugin_utilities_test.dart b/testing/dart/plugin_utilities_test.dart new file mode 100644 index 0000000000000..a387213910a0f --- /dev/null +++ b/testing/dart/plugin_utilities_test.dart @@ -0,0 +1,90 @@ +// Copyright 2018 The Chromium 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 'dart:io'; +import 'dart:ui'; + +import 'package:test/test.dart'; + +String top() => "top"; + +class Foo { + const Foo(); + static int getInt() => 1; + double getDouble() => 1.0; +} + +const Foo foo = const Foo(); + +void main() { + test('PluginUtilities.getNameOf*', () { + expect(PluginUtilities.getNameOfFunction(top), "top"); + expect(PluginUtilities.getNameOfFunction(Foo.getInt), "getInt"); + expect(PluginUtilities.getNameOfFunction(foo.getDouble), 'getDouble'); + expect(() => PluginUtilities.getNameOfFunction(null), + throwsA(const isInstanceOf())); + + expect(PluginUtilities.getNameOfFunctionClass(top), null); + expect(PluginUtilities.getNameOfFunctionClass(Foo.getInt), 'Foo'); + expect(() => PluginUtilities.getNameOfFunctionClass(null), + throwsA(const isInstanceOf())); + + // Can't lookup class name for instance functions. + expect(PluginUtilities.getNameOfFunctionClass(foo.getDouble), isNull); + }); + + test('PluginUtilities.getPathForFunctionLibrary', () { + const String file = 'plugin_utilities_test.dart'; + expect( + PluginUtilities.getPathForFunctionLibrary(top).endsWith(file), isTrue); + expect(PluginUtilities.getPathForFunctionLibrary(Foo.getInt).endsWith(file), + isTrue); + expect( + PluginUtilities.getPathForFunctionLibrary(foo.getDouble).endsWith(file), + isTrue); + + expect(() => PluginUtilities.getPathForFunctionLibrary(null), + throwsA(const isInstanceOf())); + }); + + test('PluginUtilities.getClosureByName', () { + final String getIntName = PluginUtilities.getNameOfFunction(Foo.getInt); + final String getDoubleName = + PluginUtilities.getNameOfFunction(foo.getDouble); + final String topName = PluginUtilities.getNameOfFunction(top); + final String fooName = PluginUtilities.getNameOfFunctionClass(Foo.getInt); + final String libName = PluginUtilities.getPathForFunctionLibrary(top); + + // We should successfully get a closure for top level and static methods. + expect( + PluginUtilities.getClosureByName( + name: getIntName, libraryPath: libName, className: fooName)(), + 1); + expect( + PluginUtilities.getClosureByName(name: topName, libraryPath: libName)(), + 'top'); + + // We don't support getting closures for instance methods. + expect( + PluginUtilities.getClosureByName( + name: getDoubleName, libraryPath: libName, className: fooName), + null); + + // Try an invalid function name. + expect(PluginUtilities.getClosureByName(name: 'baz'), null); + expect(() => PluginUtilities.getClosureByName(), + throwsA(const isInstanceOf())); + + // Lookup from root library. + expect( + PluginUtilities.getClosureByName( + name: getIntName, className: fooName)(), + 1); + expect(PluginUtilities.getClosureByName(name: topName)(), 'top'); + expect( + PluginUtilities.getClosureByName( + name: getDoubleName, className: fooName), + null); + }); +} From b15e35c52fe04c5763bf64d7aa3a4a4468e87cfa Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 20 Jun 2018 15:13:22 -0700 Subject: [PATCH 05/22] Updated documentation for getClosureByName --- lib/ui/plugins.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index 34c919ec5581f..4f36309b71b28 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -9,10 +9,16 @@ abstract class PluginUtilities { /// Get a closure instance for a specific static or top-level function given /// a name. /// + /// **Warning:** if the function corresponding with `name` is not referenced + /// explicitly (e.g., invoked, passed as a closure, etc.) it may be optimized + /// out of the compiled application. To prevent this, avoid hard coding names + /// as [String]s and prefer to use `PluginUtilities.getNameOfFunction` to + /// retrieve the function's name. + /// /// `name` is the name of the function we want a closure for. This is a /// required parameter. /// - /// `libraryPat h` is the path which points to the library which contains the + /// `libraryPath` is the path which points to the library which contains the /// function of interest. This path can be retrieved using /// [PluginUtilities.getPathForFunctionLibrary]. If not specified, the root /// library will be used for the function lookup. From 980622286915a5f2ec0a8d01b73e1c04fc9dc45b Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Mon, 25 Jun 2018 10:02:02 -0700 Subject: [PATCH 06/22] Updated docs for plugins.dart and changed ArgumentErrors to asserts --- lib/ui/plugins.dart | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index 4f36309b71b28..1c32619db1f64 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -11,12 +11,12 @@ abstract class PluginUtilities { /// /// **Warning:** if the function corresponding with `name` is not referenced /// explicitly (e.g., invoked, passed as a closure, etc.) it may be optimized - /// out of the compiled application. To prevent this, avoid hard coding names + /// out of the compiled application. To prevent this, avoid hardcoding names /// as [String]s and prefer to use `PluginUtilities.getNameOfFunction` to /// retrieve the function's name. /// - /// `name` is the name of the function we want a closure for. This is a - /// required parameter. + /// `name` is the name of the function we want a closure for. This must not + /// be `null`. /// /// `libraryPath` is the path which points to the library which contains the /// function of interest. This path can be retrieved using @@ -30,45 +30,41 @@ abstract class PluginUtilities { /// Returns a closure for `name` as a [Function] if the lookup was successful. /// Otherwise, `null` is returned on error. static Function getClosureByName({String name, String libraryPath, String className}) { - if (name == null) { - throw new ArgumentError.notNull('name'); - } + assert(name != null, "'name' must not be null."); return _lookupClosure(name, libraryPath, className); } /// Get the path for the library which contains a given method. /// /// `closure` is the closure of the function that we want to find the library - /// path for. + /// path for. This must not be `null`. /// /// Returns a [String] representing the path to the library which contains - /// `closure`. Returns `null` if an error occurs or `closure` is not found + /// `closure`. Returns `null` if an error occurs or `closure` is not found. static String getPathForFunctionLibrary(Function closure) { - if (closure == null) { - throw new ArgumentError.notNull('closure'); - } + assert(closure != null, "'closure' must not be null."); return _getFunctionLibraryUrl(closure); } /// Get the name of a [Function] as a [String]. + /// + /// `closure` must not be `null`. /// /// Returns a [String] representing the name of the function if the function /// exists, otherwise `null` is returned. static String getNameOfFunction(Function closure) { - if (closure == null) { - throw new ArgumentError.notNull('closure'); - } + assert(closure != null, "'closure' must not be null."); return _getFunctionName(closure); } /// Get the name of a class containing [Function] as a [String]. + /// + /// `closure` must not be `null. /// /// Returns a [String] representing the name of the function if the function /// exists and is a member of a class, otherwise `null` is returned. static String getNameOfFunctionClass(Function closure) { - if(closure == null) { - throw new ArgumentError.notNull('closure'); - } + assert(closure != null, "'closure' must not be null."); return _getNameOfFunctionClass(closure); } } From 3341e83e0714d3fbd2ae6d3ecc7c671c56d662e4 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Mon, 25 Jun 2018 12:22:28 -0700 Subject: [PATCH 07/22] Removed unused method and s/`null`/null/g --- lib/ui/plugins.dart | 16 ++++++++-------- .../ios/framework/Source/FlutterChannels.mm | 5 ----- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index 1c32619db1f64..98f44c42c9b84 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -16,7 +16,7 @@ abstract class PluginUtilities { /// retrieve the function's name. /// /// `name` is the name of the function we want a closure for. This must not - /// be `null`. + /// be null. /// /// `libraryPath` is the path which points to the library which contains the /// function of interest. This path can be retrieved using @@ -28,7 +28,7 @@ abstract class PluginUtilities { /// not provided, `name` is assumed to be referring to a top-level function. /// /// Returns a closure for `name` as a [Function] if the lookup was successful. - /// Otherwise, `null` is returned on error. + /// Otherwise, null is returned on error. static Function getClosureByName({String name, String libraryPath, String className}) { assert(name != null, "'name' must not be null."); return _lookupClosure(name, libraryPath, className); @@ -37,10 +37,10 @@ abstract class PluginUtilities { /// Get the path for the library which contains a given method. /// /// `closure` is the closure of the function that we want to find the library - /// path for. This must not be `null`. + /// path for. This must not be null. /// /// Returns a [String] representing the path to the library which contains - /// `closure`. Returns `null` if an error occurs or `closure` is not found. + /// `closure`. Returns null if an error occurs or `closure` is not found. static String getPathForFunctionLibrary(Function closure) { assert(closure != null, "'closure' must not be null."); return _getFunctionLibraryUrl(closure); @@ -48,10 +48,10 @@ abstract class PluginUtilities { /// Get the name of a [Function] as a [String]. /// - /// `closure` must not be `null`. + /// `closure` must not be null. /// /// Returns a [String] representing the name of the function if the function - /// exists, otherwise `null` is returned. + /// exists, otherwise null is returned. static String getNameOfFunction(Function closure) { assert(closure != null, "'closure' must not be null."); return _getFunctionName(closure); @@ -59,10 +59,10 @@ abstract class PluginUtilities { /// Get the name of a class containing [Function] as a [String]. /// - /// `closure` must not be `null. + /// `closure` must not be null. /// /// Returns a [String] representing the name of the function if the function - /// exists and is a member of a class, otherwise `null` is returned. + /// exists and is a member of a class, otherwise null is returned. static String getNameOfFunctionClass(Function closure) { assert(closure != null, "'closure' must not be null."); return _getNameOfFunctionClass(closure); diff --git a/shell/platform/darwin/ios/framework/Source/FlutterChannels.mm b/shell/platform/darwin/ios/framework/Source/FlutterChannels.mm index f783a021be42e..c9a75b0f49c67 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterChannels.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterChannels.mm @@ -166,11 +166,6 @@ + (instancetype)methodChannelWithName:(NSString*)name autorelease]; } -- (void)setBinaryMessenger:(NSObject*)messenger { - [_messenger release]; - _messenger = [messenger retain]; -} - - (instancetype)initWithName:(NSString*)name binaryMessenger:(NSObject*)messenger codec:(NSObject*)codec { From 8373f88bb7408d14bed1261216e7dbfbd6bea67b Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Tue, 10 Jul 2018 13:16:04 -0700 Subject: [PATCH 08/22] Updated callback lookup/passing to use handles instead of human readable strings. --- lib/ui/BUILD.gn | 2 + lib/ui/dart_runtime_hooks.cc | 105 ++++++++---------- lib/ui/natives.dart | 6 +- lib/ui/plugins.dart | 77 ++++--------- lib/ui/plugins/callback_cache.cc | 87 +++++++++++++++ lib/ui/plugins/callback_cache.h | 54 +++++++++ shell/platform/darwin/ios/BUILD.gn | 2 + .../darwin/ios/framework/Headers/Flutter.h | 1 + .../framework/Headers/FlutterCallbackCache.h | 36 ++++++ .../framework/Source/FlutterCallbackCache.mm | 23 ++++ testing/dart/plugin_utilities_test.dart | 91 ++++----------- tools/licenses/pubspec.lock | 12 +- 12 files changed, 297 insertions(+), 199 deletions(-) create mode 100644 lib/ui/plugins/callback_cache.cc create mode 100644 lib/ui/plugins/callback_cache.h create mode 100644 shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h create mode 100644 shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index c8f7e1fb21db4..272399cc464a8 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -52,6 +52,8 @@ source_set("ui") { "painting/shader.h", "painting/vertices.cc", "painting/vertices.h", + "plugins/callback_cache.cc", + "plugins/callback_cache.h", "semantics/semantics_node.cc", "semantics/semantics_node.h", "semantics/semantics_update.cc", diff --git a/lib/ui/dart_runtime_hooks.cc b/lib/ui/dart_runtime_hooks.cc index 9da3ff59fcf7e..e9b3cb32399f5 100644 --- a/lib/ui/dart_runtime_hooks.cc +++ b/lib/ui/dart_runtime_hooks.cc @@ -12,6 +12,7 @@ #include #include "flutter/common/settings.h" +#include "flutter/lib/ui/plugins/callback_cache.h" #include "flutter/lib/ui/ui_dart_state.h" #include "lib/fxl/build_config.h" #include "lib/fxl/logging.h" @@ -36,6 +37,7 @@ extern void syslog(int, const char*, ...); } #endif +using tonic::DartConverter; using tonic::LogIfError; using tonic::ToDart; @@ -49,10 +51,8 @@ namespace blink { V(Logger_PrintString, 1) \ V(SaveCompilationTrace, 0) \ V(ScheduleMicrotask, 1) \ - V(LookupClosure, 3) \ - V(GetFunctionClassName, 1) \ - V(GetFunctionLibraryUrl, 1) \ - V(GetFunctionName, 1) + V(GetCallbackHandle, 1) \ + V(GetCallbackFromHandle, 1) BUILTIN_NATIVE_LIST(DECLARE_FUNCTION); @@ -228,49 +228,14 @@ void ScheduleMicrotask(Dart_NativeArguments args) { UIDartState::Current()->ScheduleMicrotask(closure); } -void LookupClosure(Dart_NativeArguments args) { - Dart_Handle closure_name = Dart_GetNativeArgument(args, 0); - Dart_Handle library_name = Dart_GetNativeArgument(args, 1); - Dart_Handle class_name = Dart_GetNativeArgument(args, 2); - DART_CHECK_VALID(closure_name); - DART_CHECK_VALID(library_name); - DART_CHECK_VALID(class_name); - - Dart_Handle library; - if (library_name == Dart_Null()) { - library = Dart_RootLibrary(); - } else { - library = Dart_LookupLibrary(library_name); - } - DART_CHECK_VALID(library); - - Dart_Handle closure; - if (Dart_IsNull(class_name)) { - closure = Dart_GetClosure(library, closure_name); - } else { - Dart_Handle cls = Dart_GetClass(library, class_name); - DART_CHECK_VALID(cls); - if (Dart_IsNull(cls)) { - closure = Dart_Null(); - } else { - closure = Dart_GetStaticMethodClosure(library, cls, closure_name); - } - } - DART_CHECK_VALID(closure); - - Dart_SetReturnValue(args, closure); -} - -void GetFunctionLibraryUrl(Dart_NativeArguments args) { - Dart_Handle closure = Dart_GetNativeArgument(args, 0); +static std::string GetFunctionLibraryUrl(Dart_Handle closure) { if (Dart_IsClosure(closure)) { closure = Dart_ClosureFunction(closure); DART_CHECK_VALID(closure); } if (!Dart_IsFunction(closure)) { - Dart_SetReturnValue(args, Dart_Null()); - return; + return ""; } Dart_Handle url = Dart_Null(); @@ -282,11 +247,10 @@ void GetFunctionLibraryUrl(Dart_NativeArguments args) { url = Dart_LibraryUrl(owner); DART_CHECK_VALID(url); } - Dart_SetReturnValue(args, url); + return DartConverter::FromDart(url); } -void GetFunctionClassName(Dart_NativeArguments args) { - Dart_Handle closure = Dart_GetNativeArgument(args, 0); +static std::string GetFunctionClassName(Dart_Handle closure) { Dart_Handle result; if (Dart_IsClosure(closure)) { @@ -295,33 +259,26 @@ void GetFunctionClassName(Dart_NativeArguments args) { } if (!Dart_IsFunction(closure)) { - Dart_SetReturnValue(args, Dart_Null()); - return; + return ""; } bool is_static = false; result = Dart_FunctionIsStatic(closure, &is_static); DART_CHECK_VALID(result); if (!is_static) { - Dart_SetReturnValue(args, Dart_Null()); - return; + return ""; } result = Dart_FunctionOwner(closure); DART_CHECK_VALID(result); if (Dart_IsLibrary(result) || !Dart_IsInstance(result)) { - Dart_SetReturnValue(args, Dart_Null()); - return; + return ""; } - - result = Dart_ClassName(result); - DART_CHECK_VALID(result); - Dart_SetReturnValue(args, result); + return DartConverter::FromDart(Dart_ClassName(result)); } -void GetFunctionName(Dart_NativeArguments args) { - Dart_Handle func = Dart_GetNativeArgument(args, 0); +static std::string GetFunctionName(Dart_Handle func) { DART_CHECK_VALID(func); if (Dart_IsClosure(func)) { @@ -330,16 +287,44 @@ void GetFunctionName(Dart_NativeArguments args) { } if (!Dart_IsFunction(func)) { - Dart_SetReturnValue(args, Dart_Null()); - return; + return ""; + } + + bool is_static = false; + Dart_Handle result = Dart_FunctionIsStatic(func, &is_static); + DART_CHECK_VALID(result); + if (!is_static) { + return ""; } - Dart_Handle result = Dart_FunctionName(func); + result = Dart_FunctionName(func); if (Dart_IsError(result)) { Dart_PropagateError(result); + return ""; + } + + return DartConverter::FromDart(result); +} + +void GetCallbackHandle(Dart_NativeArguments args) { + Dart_Handle func = Dart_GetNativeArgument(args, 0); + std::string name = GetFunctionName(func); + std::string class_name = GetFunctionClassName(func); + std::string library_path = GetFunctionLibraryUrl(func); + + if (name.empty()) { + Dart_SetReturnValue(args, Dart_Null()); return; } - Dart_SetReturnValue(args, result); + Dart_SetReturnValue( + args, DartConverter::ToDart(DartCallbackCache::GetCallbackHandle( + name, class_name, library_path))); +} + +void GetCallbackFromHandle(Dart_NativeArguments args) { + Dart_Handle h = Dart_GetNativeArgument(args, 0); + int64_t handle = DartConverter::FromDart(h); + Dart_SetReturnValue(args, DartCallbackCache::GetCallback(handle)); } } // namespace blink diff --git a/lib/ui/natives.dart b/lib/ui/natives.dart index ab27a7edbce5b..c31ecb0b6f51a 100644 --- a/lib/ui/natives.dart +++ b/lib/ui/natives.dart @@ -48,10 +48,8 @@ dynamic _saveCompilationTrace() native 'SaveCompilationTrace'; void _scheduleMicrotask(void callback()) native 'ScheduleMicrotask'; -Function _lookupClosure(String name, String libraryPath, String className) native 'LookupClosure'; -String _getNameOfFunctionClass(Function closure) native 'GetFunctionClassName'; -String _getFunctionLibraryUrl(Function closure) native 'GetFunctionLibraryUrl'; -String _getFunctionName(Function func) native 'GetFunctionName'; +int _getCallbackHandle(Function closure) native 'GetCallbackHandle'; +Function _getCallbackFromHandle(int handle) native 'GetCallbackFromHandle'; // Required for gen_snapshot to work correctly. int _isolateId; diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index 98f44c42c9b84..efb95c234a030 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -6,65 +6,30 @@ part of dart.ui; /// Functionality for Flutter plugin authors. abstract class PluginUtilities { - /// Get a closure instance for a specific static or top-level function given - /// a name. - /// - /// **Warning:** if the function corresponding with `name` is not referenced - /// explicitly (e.g., invoked, passed as a closure, etc.) it may be optimized - /// out of the compiled application. To prevent this, avoid hardcoding names - /// as [String]s and prefer to use `PluginUtilities.getNameOfFunction` to - /// retrieve the function's name. - /// - /// `name` is the name of the function we want a closure for. This must not - /// be null. - /// - /// `libraryPath` is the path which points to the library which contains the - /// function of interest. This path can be retrieved using - /// [PluginUtilities.getPathForFunctionLibrary]. If not specified, the root - /// library will be used for the function lookup. - /// - /// `className` is the name of the class in which function `name` is defined. - /// This parameter is required for retrieving closures for static methods. If - /// not provided, `name` is assumed to be referring to a top-level function. - /// - /// Returns a closure for `name` as a [Function] if the lookup was successful. - /// Otherwise, null is returned on error. - static Function getClosureByName({String name, String libraryPath, String className}) { - assert(name != null, "'name' must not be null."); - return _lookupClosure(name, libraryPath, className); + /// Get a handle to a named top-level or static callback function which can + /// be easily passed between isolates. + /// + /// `callback` must not be null. + /// + /// Returns an integer that can be provided to + /// [PluginUtilities.getCallbackFromHandle] to retrieve a tear-off of the + /// original callback. If `callback` is not a top-level or static function, + /// null is returned. + static int getCallbackHandle(Function callback) { + assert(callback != null, "'callback' must not be null."); + return _getCallbackHandle(callback); } - /// Get the path for the library which contains a given method. - /// - /// `closure` is the closure of the function that we want to find the library - /// path for. This must not be null. + /// Get a tear-off of a named top-level or static callback represented by a + /// handle. /// - /// Returns a [String] representing the path to the library which contains - /// `closure`. Returns null if an error occurs or `closure` is not found. - static String getPathForFunctionLibrary(Function closure) { - assert(closure != null, "'closure' must not be null."); - return _getFunctionLibraryUrl(closure); - } - - /// Get the name of a [Function] as a [String]. - /// - /// `closure` must not be null. - /// - /// Returns a [String] representing the name of the function if the function - /// exists, otherwise null is returned. - static String getNameOfFunction(Function closure) { - assert(closure != null, "'closure' must not be null."); - return _getFunctionName(closure); - } - - /// Get the name of a class containing [Function] as a [String]. - /// - /// `closure` must not be null. + /// `handle` must not be null. /// - /// Returns a [String] representing the name of the function if the function - /// exists and is a member of a class, otherwise null is returned. - static String getNameOfFunctionClass(Function closure) { - assert(closure != null, "'closure' must not be null."); - return _getNameOfFunctionClass(closure); + /// If `handle` is not a valid handle returned by + /// [PluginUtilities.getCallbackHandle], null is returned. Otherwise, a + /// tear-off of the callback associated with `handle` is returned. + static Function getCallbackFromHandle(int handle) { + assert(handle != null, "'handle' must not be null."); + return _getCallbackFromHandle(handle); } } diff --git a/lib/ui/plugins/callback_cache.cc b/lib/ui/plugins/callback_cache.cc new file mode 100644 index 0000000000000..05b4d19174cc2 --- /dev/null +++ b/lib/ui/plugins/callback_cache.cc @@ -0,0 +1,87 @@ +// Copyright 2018 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/lib/ui/plugins/callback_cache.h" +#include "lib/fxl/logging.h" +#include "lib/tonic/converter/dart_converter.h" + +using tonic::ToDart; + +namespace blink { + +std::mutex DartCallbackCache::mutex_; +std::map DartCallbackCache::cache_; + +Dart_Handle DartCallbackCache::GetCallback(int64_t handle) { + std::unique_lock lock(mutex_); + auto iterator = cache_.find(handle); + if (iterator != cache_.end()) { + DartCallbackRepresentation cb = iterator->second; + return LookupDartClosure(cb.name, cb.class_name, cb.library_path); + } + return Dart_Null(); +} + +int64_t DartCallbackCache::GetCallbackHandle(const std::string& name, + const std::string& class_name, + const std::string& library_path) { + std::unique_lock lock(mutex_); + std::hash hasher; + int64_t hash = hasher(name); + hash += hasher(class_name); + hash += hasher(library_path); + + if (cache_.find(hash) == cache_.end()) { + cache_[hash] = {name, class_name, library_path}; + } + return hash; +} + +DartCallbackRepresentation DartCallbackCache::GetCallbackInformation( + int64_t handle) { + std::unique_lock lock(mutex_); + auto iterator = cache_.find(handle); + if (iterator != cache_.end()) { + return iterator->second; + } + return {"", "", ""}; +} + +Dart_Handle DartCallbackCache::LookupDartClosure( + const std::string& name, + const std::string& class_name, + const std::string& library_path) { + Dart_Handle closure_name = ToDart(name); + Dart_Handle library_name = + library_path.empty() ? Dart_Null() : ToDart(library_path); + Dart_Handle cls_name = class_name.empty() ? Dart_Null() : ToDart(class_name); + DART_CHECK_VALID(closure_name); + DART_CHECK_VALID(library_name); + DART_CHECK_VALID(cls_name); + + Dart_Handle library; + if (library_name == Dart_Null()) { + library = Dart_RootLibrary(); + } else { + library = Dart_LookupLibrary(library_name); + } + DART_CHECK_VALID(library); + + Dart_Handle closure; + if (Dart_IsNull(cls_name)) { + closure = Dart_GetClosure(library, closure_name); + } else { + Dart_Handle cls = Dart_GetClass(library, cls_name); + DART_CHECK_VALID(cls); + if (Dart_IsNull(cls)) { + closure = Dart_Null(); + } else { + closure = Dart_GetStaticMethodClosure(library, cls, closure_name); + } + } + DART_CHECK_VALID(closure); + return closure; +} + +} // namespace blink diff --git a/lib/ui/plugins/callback_cache.h b/lib/ui/plugins/callback_cache.h new file mode 100644 index 0000000000000..36cc17fd07a21 --- /dev/null +++ b/lib/ui/plugins/callback_cache.h @@ -0,0 +1,54 @@ +// Copyright 2018 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_LIB_UI_CALLBACK_CACHE_H_ +#define FLUTTER_LIB_UI_CALLBACK_CACHE_H_ + +#include +#include +#include + +#include "flutter/fml/synchronization/thread_annotations.h" +#include "lib/fxl/macros.h" +#include "third_party/dart/runtime/include/dart_api.h" + +#define DART_CALLBACK_INVALID_HANDLE -1 +#define LOCK_UNLOCK(m) FML_ACQUIRE(m) FML_RELEASE(m) + +namespace blink { + +typedef struct { + std::string name; + std::string class_name; + std::string library_path; +} DartCallbackRepresentation; + +class DartCallbackCache { + public: + static int64_t GetCallbackHandle(const std::string& name, + const std::string& class_name, + const std::string& library_path) + LOCK_UNLOCK(mutex_); + + static Dart_Handle GetCallback(int64_t handle) LOCK_UNLOCK(mutex_); + + static DartCallbackRepresentation GetCallbackInformation(int64_t handle) + LOCK_UNLOCK(mutex_); + + private: + static Dart_Handle LookupDartClosure(const std::string& name, + const std::string& class_name, + const std::string& library_path); + + static std::mutex mutex_; + + static std::map cache_ + FML_GUARDED_BY(mutex_); + + FXL_DISALLOW_IMPLICIT_CONSTRUCTORS(DartCallbackCache); +}; + +} // namespace blink + +#endif // FLUTTER_LIB_UI_CALLBACK_CACHE_H_ diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 6beb227ed0c4a..8e0fb443f5f27 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -22,6 +22,7 @@ _flutter_framework_headers = [ "framework/Headers/Flutter.h", "framework/Headers/FlutterAppDelegate.h", "framework/Headers/FlutterBinaryMessenger.h", + "framework/Headers/FlutterCallbackCache.h", "framework/Headers/FlutterChannels.h", "framework/Headers/FlutterCodecs.h", "framework/Headers/FlutterDartProject.h", @@ -44,6 +45,7 @@ shared_library("create_flutter_framework_dylib") { sources = [ "framework/Source/FlutterAppDelegate.mm", "framework/Source/FlutterAppDelegate_Internal.h", + "framework/Source/FlutterCallbackCache.mm", "framework/Source/FlutterChannels.mm", "framework/Source/FlutterCodecs.mm", "framework/Source/FlutterDartProject.mm", diff --git a/shell/platform/darwin/ios/framework/Headers/Flutter.h b/shell/platform/darwin/ios/framework/Headers/Flutter.h index d850854f2f517..ddadf8431368a 100644 --- a/shell/platform/darwin/ios/framework/Headers/Flutter.h +++ b/shell/platform/darwin/ios/framework/Headers/Flutter.h @@ -36,6 +36,7 @@ #include "FlutterAppDelegate.h" #include "FlutterBinaryMessenger.h" +#include "FlutterCallbackCache.h" #include "FlutterChannels.h" #include "FlutterCodecs.h" #include "FlutterDartProject.h" diff --git a/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h b/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h new file mode 100644 index 0000000000000..1559f61158f89 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h @@ -0,0 +1,36 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FLUTTERCALLBACKCACHE_H_ +#define FLUTTER_FLUTTERCALLBACKCACHE_H_ + +#import + +#include "FlutterMacros.h" + +FLUTTER_EXPORT +@interface FlutterCallbackInformation : NSObject +@property(retain) NSString* callbackName; +@property(retain) NSString* callbackClassName; +@property(retain) NSString* callbackLibraryPath; +@end + +FLUTTER_EXPORT +@interface FlutterCallbackCache : NSObject +/** + Returns the callback information for the given callback handle. + This callback information can be used when spawning a + FlutterHeadlessDartRunner. + + - Parameter handle: The handle for a callback, provided by the + Dart method `PluginUtilities.getCallbackHandle`. + - Returns: A FlutterCallbackInformation object which contains the name of the + callback, the name of the class in which the callback is defined, and the + path of the library which contains the callback. + */ ++ (FlutterCallbackInformation*)lookupCallbackInformation:(int64_t)handle; + +@end + +#endif // FLUTTER_FLUTTERCALLBACKCACHE_H_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm b/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm new file mode 100644 index 0000000000000..9c3332547b856 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm @@ -0,0 +1,23 @@ +// Copyright 2018 The Chromium 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/framework/Headers/FlutterCallbackCache.h" + +#include "flutter/lib/ui/plugins/callback_cache.h" + +@implementation FlutterCallbackInformation +@end + +@implementation FlutterCallbackCache + ++ (FlutterCallbackInformation*)lookupCallbackInformation:(int64_t)handle { + blink::DartCallbackRepresentation info = blink::DartCallbackCache::GetCallbackInformation(handle); + FlutterCallbackInformation* new_info = [[FlutterCallbackInformation alloc] init]; + new_info.callbackName = [NSString stringWithUTF8String:info.name.c_str()]; + new_info.callbackClassName = [NSString stringWithUTF8String:info.class_name.c_str()]; + new_info.callbackLibraryPath = [NSString stringWithUTF8String:info.library_path.c_str()]; + return new_info; +} + +@end \ No newline at end of file diff --git a/testing/dart/plugin_utilities_test.dart b/testing/dart/plugin_utilities_test.dart index a387213910a0f..89f43824bc2dc 100644 --- a/testing/dart/plugin_utilities_test.dart +++ b/testing/dart/plugin_utilities_test.dart @@ -2,7 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:io'; import 'dart:ui'; import 'package:test/test.dart'; @@ -18,73 +17,27 @@ class Foo { const Foo foo = const Foo(); void main() { - test('PluginUtilities.getNameOf*', () { - expect(PluginUtilities.getNameOfFunction(top), "top"); - expect(PluginUtilities.getNameOfFunction(Foo.getInt), "getInt"); - expect(PluginUtilities.getNameOfFunction(foo.getDouble), 'getDouble'); - expect(() => PluginUtilities.getNameOfFunction(null), - throwsA(const isInstanceOf())); - - expect(PluginUtilities.getNameOfFunctionClass(top), null); - expect(PluginUtilities.getNameOfFunctionClass(Foo.getInt), 'Foo'); - expect(() => PluginUtilities.getNameOfFunctionClass(null), - throwsA(const isInstanceOf())); - - // Can't lookup class name for instance functions. - expect(PluginUtilities.getNameOfFunctionClass(foo.getDouble), isNull); - }); - - test('PluginUtilities.getPathForFunctionLibrary', () { - const String file = 'plugin_utilities_test.dart'; - expect( - PluginUtilities.getPathForFunctionLibrary(top).endsWith(file), isTrue); - expect(PluginUtilities.getPathForFunctionLibrary(Foo.getInt).endsWith(file), - isTrue); - expect( - PluginUtilities.getPathForFunctionLibrary(foo.getDouble).endsWith(file), - isTrue); - - expect(() => PluginUtilities.getPathForFunctionLibrary(null), - throwsA(const isInstanceOf())); - }); - - test('PluginUtilities.getClosureByName', () { - final String getIntName = PluginUtilities.getNameOfFunction(Foo.getInt); - final String getDoubleName = - PluginUtilities.getNameOfFunction(foo.getDouble); - final String topName = PluginUtilities.getNameOfFunction(top); - final String fooName = PluginUtilities.getNameOfFunctionClass(Foo.getInt); - final String libName = PluginUtilities.getPathForFunctionLibrary(top); - - // We should successfully get a closure for top level and static methods. - expect( - PluginUtilities.getClosureByName( - name: getIntName, libraryPath: libName, className: fooName)(), - 1); - expect( - PluginUtilities.getClosureByName(name: topName, libraryPath: libName)(), - 'top'); - - // We don't support getting closures for instance methods. - expect( - PluginUtilities.getClosureByName( - name: getDoubleName, libraryPath: libName, className: fooName), - null); - - // Try an invalid function name. - expect(PluginUtilities.getClosureByName(name: 'baz'), null); - expect(() => PluginUtilities.getClosureByName(), - throwsA(const isInstanceOf())); - - // Lookup from root library. - expect( - PluginUtilities.getClosureByName( - name: getIntName, className: fooName)(), - 1); - expect(PluginUtilities.getClosureByName(name: topName)(), 'top'); - expect( - PluginUtilities.getClosureByName( - name: getDoubleName, className: fooName), - null); + test('PluginUtilities Callback Handles', () { + // Top level callback. + final hTop = PluginUtilities.getCallbackHandle(top); + expect(hTop, isNotNull); + expect(hTop, isNot(0)); + expect(PluginUtilities.getCallbackHandle(top), hTop); + final topClosure = PluginUtilities.getCallbackFromHandle(hTop); + expect(topClosure, isNotNull); + expect(topClosure(), "top"); + + // Static method callback + final hGetInt = PluginUtilities.getCallbackHandle(Foo.getInt); + expect(hGetInt, isNotNull); + expect(hGetInt, isNot(0)); + expect(PluginUtilities.getCallbackHandle(Foo.getInt), hGetInt); + final getIntClosure = PluginUtilities.getCallbackFromHandle(hGetInt); + expect(getIntClosure, isNotNull); + expect(getIntClosure(), 1); + + // Instance method callbacks cannot be looked up. + final foo = new Foo(); + expect(PluginUtilities.getCallbackHandle(foo.getDouble), isNull); }); } diff --git a/tools/licenses/pubspec.lock b/tools/licenses/pubspec.lock index 545aa1144973f..75d0f144fde64 100644 --- a/tools/licenses/pubspec.lock +++ b/tools/licenses/pubspec.lock @@ -1,61 +1,53 @@ # Generated by pub -# See https://www.dartlang.org/tools/pub/glossary#lockfile +# See http://pub.dartlang.org/doc/glossary.html#lockfile packages: archive: - dependency: "direct main" description: name: archive url: "https://pub.dartlang.org" source: hosted version: "1.0.33" args: - dependency: "direct main" description: name: args url: "https://pub.dartlang.org" source: hosted version: "0.13.7" charcode: - dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted version: "1.1.1" collection: - dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted version: "1.14.5" convert: - dependency: transitive description: name: convert url: "https://pub.dartlang.org" source: hosted version: "2.0.1" crypto: - dependency: "direct main" description: name: crypto url: "https://pub.dartlang.org" source: hosted version: "2.0.2+1" path: - dependency: "direct main" description: name: path url: "https://pub.dartlang.org" source: hosted version: "1.5.1" typed_data: - dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted version: "1.1.5" sdks: - dart: ">=1.21.0 <=2.0.0-edge.2b36f923d95a41b2f1c5cbb5edd9872f68c18112" + dart: ">=1.21.0 <2.0.0" From f4d23c25e9b09c3d88ad5c40da7e98b493f447ef Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 11 Jul 2018 10:45:28 -0700 Subject: [PATCH 09/22] Added CallbackHandle wrapper for handles returned from PluginUtilities.getCallbackHandle --- lib/ui/plugins.dart | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index efb95c234a030..bf4ea539502a6 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -4,6 +4,32 @@ part of dart.ui; +/// An wrapper for a raw callback handle. +/// +/// This class should only be instantiated +class CallbackHandle { + final int _handle; + + /// Create an instance using a raw callback handle. + /// + /// Only values produced by a call to [CallbackHandle.toRawHandle] should be + /// used, otherwise this object will be an invalid handle. + CallbackHandle.fromRawHandle(this._handle) { + assert(_handle != null, "'_handle' must not be null."); + } + + /// Get the raw callback handle to pass over a [MethodChannel] or isolate + /// port. + int toRawHandle() => _handle; + + @override + int get hashCode => _handle; + + @override + bool operator ==(other) => + ((other is CallbackHandle) && (_handle == other._handle)); +} + /// Functionality for Flutter plugin authors. abstract class PluginUtilities { /// Get a handle to a named top-level or static callback function which can @@ -11,13 +37,13 @@ abstract class PluginUtilities { /// /// `callback` must not be null. /// - /// Returns an integer that can be provided to + /// Returns a [CallbackHandle] that can be provided to /// [PluginUtilities.getCallbackFromHandle] to retrieve a tear-off of the /// original callback. If `callback` is not a top-level or static function, /// null is returned. - static int getCallbackHandle(Function callback) { + static CallbackHandle getCallbackHandle(Function callback) { assert(callback != null, "'callback' must not be null."); - return _getCallbackHandle(callback); + return new CallbackHandle.fromRawHandle(_getCallbackHandle(callback)); } /// Get a tear-off of a named top-level or static callback represented by a @@ -28,8 +54,8 @@ abstract class PluginUtilities { /// If `handle` is not a valid handle returned by /// [PluginUtilities.getCallbackHandle], null is returned. Otherwise, a /// tear-off of the callback associated with `handle` is returned. - static Function getCallbackFromHandle(int handle) { + static Function getCallbackFromHandle(CallbackHandle handle) { assert(handle != null, "'handle' must not be null."); - return _getCallbackFromHandle(handle); + return _getCallbackFromHandle(handle.toRawHandle()); } } From 87d3d8011c2c6a092deea2458f7c08998a01b07b Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 11 Jul 2018 13:06:58 -0700 Subject: [PATCH 10/22] Updated licenses --- travis/licenses_golden/licenses_flutter | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index b56c740bdbf55..e2be01dbc582a 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -494,7 +494,9 @@ FILE: ../../../flutter/lib/ui/plugins.dart FILE: ../../../flutter/lib/ui/text/asset_manager_font_provider.cc FILE: ../../../flutter/lib/ui/text/asset_manager_font_provider.h FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm @@ -586,6 +588,8 @@ FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.cc FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server.h FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.cc FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.h +FILE: ../../../flutter/lib/ui/plugins/callback_cache.cc +FILE: ../../../flutter/lib/ui/plugins/callback_cache.h FILE: ../../../flutter/shell/common/isolate_configuration.cc FILE: ../../../flutter/shell/common/isolate_configuration.h FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc From 14e7aca95182fa18effa82e5da31c4459a2d23a3 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 11 Jul 2018 13:51:25 -0700 Subject: [PATCH 11/22] Fixed analyzer complaints --- lib/ui/plugins.dart | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index bf4ea539502a6..cd5f0593d464a 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -5,8 +5,6 @@ part of dart.ui; /// An wrapper for a raw callback handle. -/// -/// This class should only be instantiated class CallbackHandle { final int _handle; @@ -14,9 +12,8 @@ class CallbackHandle { /// /// Only values produced by a call to [CallbackHandle.toRawHandle] should be /// used, otherwise this object will be an invalid handle. - CallbackHandle.fromRawHandle(this._handle) { - assert(_handle != null, "'_handle' must not be null."); - } + CallbackHandle.fromRawHandle(this._handle) + : assert(_handle != null, "'_handle' must not be null."); /// Get the raw callback handle to pass over a [MethodChannel] or isolate /// port. @@ -26,8 +23,8 @@ class CallbackHandle { int get hashCode => _handle; @override - bool operator ==(other) => - ((other is CallbackHandle) && (_handle == other._handle)); + bool operator ==(dynamic other) => + (other is CallbackHandle) && (_handle == other._handle); } /// Functionality for Flutter plugin authors. From 2ff769004ecc06841b076fca00abac3328e58b4b Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 11 Jul 2018 14:46:00 -0700 Subject: [PATCH 12/22] Update licenses_flutter --- travis/licenses_golden/licenses_flutter | 1 + 1 file changed, 1 insertion(+) diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index ea556cbad1389..79dc2893889f1 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -502,6 +502,7 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/Platfor FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewRegistry.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewRegistryImpl.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPluginAppLifeCycleDelegate.mm From 48261fd3145c9a98cca23e7d82a9ffca457fba87 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 11 Jul 2018 14:56:01 -0700 Subject: [PATCH 13/22] Update licenses_flutter --- travis/licenses_golden/licenses_flutter | 1 - 1 file changed, 1 deletion(-) diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index 79dc2893889f1..29035a43eb7ae 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -496,7 +496,6 @@ FILE: ../../../flutter/lib/ui/semantics/custom_accessibility_action.h FILE: ../../../flutter/lib/ui/text/asset_manager_font_provider.cc FILE: ../../../flutter/lib/ui/text/asset_manager_font_provider.h FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformView.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewFactory.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewRegistry.java From abcabee3cd021769959d51bf02ad285d0b23ddb1 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 11 Jul 2018 15:57:29 -0700 Subject: [PATCH 14/22] Updated docs for plugins.dart Added sentences stating that objects returned from getCallbackHandle and getCallbackFromHandle should be cached to avoid potentially expensive lookups. --- lib/ui/plugins.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index cd5f0593d464a..2f8b145a91caa 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -38,6 +38,9 @@ abstract class PluginUtilities { /// [PluginUtilities.getCallbackFromHandle] to retrieve a tear-off of the /// original callback. If `callback` is not a top-level or static function, /// null is returned. + /// + /// The result of this method should be cached in order to avoid repeated + /// and potentially expensive lookups. static CallbackHandle getCallbackHandle(Function callback) { assert(callback != null, "'callback' must not be null."); return new CallbackHandle.fromRawHandle(_getCallbackHandle(callback)); @@ -51,6 +54,9 @@ abstract class PluginUtilities { /// If `handle` is not a valid handle returned by /// [PluginUtilities.getCallbackHandle], null is returned. Otherwise, a /// tear-off of the callback associated with `handle` is returned. + /// + /// The result of this method should be cached in order to avoid repeated + /// and potentially expensive lookups. static Function getCallbackFromHandle(CallbackHandle handle) { assert(handle != null, "'handle' must not be null."); return _getCallbackFromHandle(handle.toRawHandle()); From 2ec1ef4799b2192bee420ee64b60a77a39251396 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Wed, 11 Jul 2018 16:38:11 -0700 Subject: [PATCH 15/22] Added caching in PluginUtilities --- lib/ui/plugins.dart | 17 +++++++++-------- shell/platform/darwin/ios/platform_view_ios.h | 3 --- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index 2f8b145a91caa..1fad408c8f49a 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -29,6 +29,11 @@ class CallbackHandle { /// Functionality for Flutter plugin authors. abstract class PluginUtilities { + static Map _forwardCache = + new Map(); + static Map _backwardCache = + new Map(); + /// Get a handle to a named top-level or static callback function which can /// be easily passed between isolates. /// @@ -38,12 +43,10 @@ abstract class PluginUtilities { /// [PluginUtilities.getCallbackFromHandle] to retrieve a tear-off of the /// original callback. If `callback` is not a top-level or static function, /// null is returned. - /// - /// The result of this method should be cached in order to avoid repeated - /// and potentially expensive lookups. static CallbackHandle getCallbackHandle(Function callback) { assert(callback != null, "'callback' must not be null."); - return new CallbackHandle.fromRawHandle(_getCallbackHandle(callback)); + return _forwardCache.putIfAbsent(callback, + () => new CallbackHandle.fromRawHandle(_getCallbackHandle(callback))); } /// Get a tear-off of a named top-level or static callback represented by a @@ -54,11 +57,9 @@ abstract class PluginUtilities { /// If `handle` is not a valid handle returned by /// [PluginUtilities.getCallbackHandle], null is returned. Otherwise, a /// tear-off of the callback associated with `handle` is returned. - /// - /// The result of this method should be cached in order to avoid repeated - /// and potentially expensive lookups. static Function getCallbackFromHandle(CallbackHandle handle) { assert(handle != null, "'handle' must not be null."); - return _getCallbackFromHandle(handle.toRawHandle()); + return _backwardCache.putIfAbsent( + handle, () => _getCallbackFromHandle(handle.toRawHandle())); } } diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index 4f13b4c8d37e4..8d1de7a0c092a 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -57,9 +57,6 @@ class PlatformViewIOS final : public HeadlessPlatformViewIOS { // |shell::PlatformView| void SetSemanticsEnabled(bool enabled) override; - // |shell::PlatformView| - void HandlePlatformMessage( - fxl::RefPtr message) override; // |shell::PlatformView| void UpdateSemantics(blink::SemanticsNodeUpdates update, From 8cc4394e35900f95d036f2643b5095fecc45ff9d Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Thu, 12 Jul 2018 09:30:43 -0700 Subject: [PATCH 16/22] Fix analyzer issues --- analysis_options.yaml | 2 +- lib/ui/plugins.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 5ceb890d98720..4ae940d7cd1a9 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -42,7 +42,7 @@ linter: # - avoid_bool_literals_in_conditional_expressions # not yet tested # - avoid_catches_without_on_clauses # we do this commonly # - avoid_catching_errors # we do this commonly - - avoid_classes_with_only_static_members + # - avoid_classes_with_only_static_members # required for PluginUtilities caching / lookup methods - avoid_empty_else - avoid_function_literals_in_foreach_calls - avoid_init_to_null diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index 1fad408c8f49a..908bee35f8424 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -30,9 +30,9 @@ class CallbackHandle { /// Functionality for Flutter plugin authors. abstract class PluginUtilities { static Map _forwardCache = - new Map(); + {}; static Map _backwardCache = - new Map(); + {}; /// Get a handle to a named top-level or static callback function which can /// be easily passed between isolates. From 81492d65cb69b6dfebf0dc0639abb58a3f9d5e58 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Thu, 12 Jul 2018 12:06:13 -0700 Subject: [PATCH 17/22] Addressed comments --- lib/ui/plugins/callback_cache.cc | 8 ++++---- lib/ui/plugins/callback_cache.h | 5 +++-- .../ios/framework/Headers/FlutterCallbackCache.h | 3 ++- .../ios/framework/Source/FlutterCallbackCache.mm | 11 +++++++---- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/ui/plugins/callback_cache.cc b/lib/ui/plugins/callback_cache.cc index 05b4d19174cc2..ad31891a2f90c 100644 --- a/lib/ui/plugins/callback_cache.cc +++ b/lib/ui/plugins/callback_cache.cc @@ -38,14 +38,14 @@ int64_t DartCallbackCache::GetCallbackHandle(const std::string& name, return hash; } -DartCallbackRepresentation DartCallbackCache::GetCallbackInformation( - int64_t handle) { +std::unique_ptr +DartCallbackCache::GetCallbackInformation(int64_t handle) { std::unique_lock lock(mutex_); auto iterator = cache_.find(handle); if (iterator != cache_.end()) { - return iterator->second; + return std::make_unique(iterator->second); } - return {"", "", ""}; + return nullptr; } Dart_Handle DartCallbackCache::LookupDartClosure( diff --git a/lib/ui/plugins/callback_cache.h b/lib/ui/plugins/callback_cache.h index 36cc17fd07a21..a32dfcbbcf02c 100644 --- a/lib/ui/plugins/callback_cache.h +++ b/lib/ui/plugins/callback_cache.h @@ -6,6 +6,7 @@ #define FLUTTER_LIB_UI_CALLBACK_CACHE_H_ #include +#include #include #include @@ -33,8 +34,8 @@ class DartCallbackCache { static Dart_Handle GetCallback(int64_t handle) LOCK_UNLOCK(mutex_); - static DartCallbackRepresentation GetCallbackInformation(int64_t handle) - LOCK_UNLOCK(mutex_); + static std::unique_ptr GetCallbackInformation( + int64_t handle) LOCK_UNLOCK(mutex_); private: static Dart_Handle LookupDartClosure(const std::string& name, diff --git a/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h b/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h index 1559f61158f89..7150838fafbb3 100644 --- a/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h +++ b/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h @@ -27,7 +27,8 @@ FLUTTER_EXPORT Dart method `PluginUtilities.getCallbackHandle`. - Returns: A FlutterCallbackInformation object which contains the name of the callback, the name of the class in which the callback is defined, and the - path of the library which contains the callback. + path of the library which contains the callback. If the provided handle is + invalid, nil is returned. */ + (FlutterCallbackInformation*)lookupCallbackInformation:(int64_t)handle; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm b/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm index 9c3332547b856..61ff0b165d385 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm @@ -12,11 +12,14 @@ @implementation FlutterCallbackInformation @implementation FlutterCallbackCache + (FlutterCallbackInformation*)lookupCallbackInformation:(int64_t)handle { - blink::DartCallbackRepresentation info = blink::DartCallbackCache::GetCallbackInformation(handle); + auto info = blink::DartCallbackCache::GetCallbackInformation(handle); + if (info == nullptr) { + return nil; + } FlutterCallbackInformation* new_info = [[FlutterCallbackInformation alloc] init]; - new_info.callbackName = [NSString stringWithUTF8String:info.name.c_str()]; - new_info.callbackClassName = [NSString stringWithUTF8String:info.class_name.c_str()]; - new_info.callbackLibraryPath = [NSString stringWithUTF8String:info.library_path.c_str()]; + new_info.callbackName = [NSString stringWithUTF8String:info->name.c_str()]; + new_info.callbackClassName = [NSString stringWithUTF8String:info->class_name.c_str()]; + new_info.callbackLibraryPath = [NSString stringWithUTF8String:info->library_path.c_str()]; return new_info; } From 514df89ec00f1599b640165f678e489663e8605b Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Thu, 12 Jul 2018 14:52:33 -0700 Subject: [PATCH 18/22] Update analysis_options.yaml --- analysis_options.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 4ae940d7cd1a9..6420a5457adca 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -42,7 +42,7 @@ linter: # - avoid_bool_literals_in_conditional_expressions # not yet tested # - avoid_catches_without_on_clauses # we do this commonly # - avoid_catching_errors # we do this commonly - # - avoid_classes_with_only_static_members # required for PluginUtilities caching / lookup methods + - avoid_classes_with_only_static_members # We want to avoid classes that can be instantiated but only have statics - avoid_empty_else - avoid_function_literals_in_foreach_calls - avoid_init_to_null From c6a955d01868f35785290364538257c27a69f7ea Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Thu, 12 Jul 2018 14:54:45 -0700 Subject: [PATCH 19/22] Added private factory to make analyzer happy --- lib/ui/plugins.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/ui/plugins.dart b/lib/ui/plugins.dart index 908bee35f8424..215c52124763b 100644 --- a/lib/ui/plugins.dart +++ b/lib/ui/plugins.dart @@ -29,6 +29,10 @@ class CallbackHandle { /// Functionality for Flutter plugin authors. abstract class PluginUtilities { + // This class is only a namespace, and should not be instantiated or + // extended directly. + factory PluginUtilities._() => null; + static Map _forwardCache = {}; static Map _backwardCache = From 2ba3d6b7b85652ff5295a27662e438a6a6a05ee9 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Fri, 3 Aug 2018 16:50:59 -0700 Subject: [PATCH 20/22] Updated background execution implementation for Android (#5640) * Updated background execution implementation for Android --- shell/platform/android/BUILD.gn | 2 + .../platform/android/android_shell_holder.cc | 75 +++++++---- shell/platform/android/android_shell_holder.h | 3 +- .../flutter/app/FlutterActivityDelegate.java | 24 ++-- .../view/FlutterCallbackInformation.java | 34 +++++ .../io/flutter/view/FlutterNativeView.java | 119 ++++++++++-------- .../io/flutter/view/FlutterRunArguments.java | 16 +++ .../android/io/flutter/view/FlutterView.java | 30 ++++- .../platform/android/platform_view_android.cc | 27 +++- .../platform/android/platform_view_android.h | 7 ++ .../android/platform_view_android_jni.cc | 82 ++++++++++-- tools/licenses/pubspec.lock | 12 +- travis/licenses_golden/licenses_flutter | 2 + 13 files changed, 328 insertions(+), 105 deletions(-) create mode 100644 shell/platform/android/io/flutter/view/FlutterCallbackInformation.java create mode 100644 shell/platform/android/io/flutter/view/FlutterRunArguments.java diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 817c1c29250f8..1548cee47cdec 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -132,8 +132,10 @@ java_library("flutter_shell_java") { "io/flutter/util/PathUtils.java", "io/flutter/util/Preconditions.java", "io/flutter/view/AccessibilityBridge.java", + "io/flutter/view/FlutterCallbackInformation.java", "io/flutter/view/FlutterMain.java", "io/flutter/view/FlutterNativeView.java", + "io/flutter/view/FlutterRunArguments.java", "io/flutter/view/FlutterView.java", "io/flutter/view/ResourceCleaner.java", "io/flutter/view/ResourceExtractor.java", diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index 248949535d06f..efd239d65ae40 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -23,7 +23,8 @@ namespace shell { AndroidShellHolder::AndroidShellHolder( blink::Settings settings, - fml::jni::JavaObjectWeakGlobalRef java_object) + fml::jni::JavaObjectWeakGlobalRef java_object, + bool is_background_view) : settings_(std::move(settings)), java_object_(java_object) { static size_t shell_count = 1; auto thread_label = std::to_string(shell_count++); @@ -31,26 +32,42 @@ AndroidShellHolder::AndroidShellHolder( FXL_CHECK(pthread_key_create(&thread_destruct_key_, ThreadDestructCallback) == 0); - thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU | - ThreadHost::Type::IO}; + if (is_background_view) { + thread_host_ = {thread_label, ThreadHost::Type::UI}; + } else { + thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU | + ThreadHost::Type::IO}; + } // Detach from JNI when the UI and GPU threads exit. auto jni_exit_task([key = thread_destruct_key_]() { FXL_CHECK(pthread_setspecific(key, reinterpret_cast(1)) == 0); }); thread_host_.ui_thread->GetTaskRunner()->PostTask(jni_exit_task); - thread_host_.gpu_thread->GetTaskRunner()->PostTask(jni_exit_task); + if (!is_background_view) { + thread_host_.gpu_thread->GetTaskRunner()->PostTask(jni_exit_task); + } fml::WeakPtr weak_platform_view; Shell::CreateCallback on_create_platform_view = - [java_object, &weak_platform_view](Shell& shell) { - auto platform_view_android = std::make_unique( - shell, // delegate - shell.GetTaskRunners(), // task runners - java_object, // java object handle for JNI interop - shell.GetSettings() - .enable_software_rendering // use software rendering - ); + [is_background_view, java_object, &weak_platform_view](Shell& shell) { + std::unique_ptr platform_view_android; + if (is_background_view) { + platform_view_android = std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + java_object // java object handle for JNI interop + ); + + } else { + platform_view_android = std::make_unique( + shell, // delegate + shell.GetTaskRunners(), // task runners + java_object, // java object handle for JNI interop + shell.GetSettings() + .enable_software_rendering // use software rendering + ); + } weak_platform_view = platform_view_android->GetWeakPtr(); return platform_view_android; }; @@ -62,13 +79,27 @@ AndroidShellHolder::AndroidShellHolder( // The current thread will be used as the platform thread. Ensure that the // message loop is initialized. fml::MessageLoop::EnsureInitializedForCurrentThread(); - + fxl::RefPtr gpu_runner; + fxl::RefPtr ui_runner; + fxl::RefPtr io_runner; + fxl::RefPtr platform_runner = + fml::MessageLoop::GetCurrent().GetTaskRunner(); + if (is_background_view) { + auto single_task_runner = thread_host_.ui_thread->GetTaskRunner(); + gpu_runner = single_task_runner; + ui_runner = single_task_runner; + io_runner = single_task_runner; + } else { + gpu_runner = thread_host_.gpu_thread->GetTaskRunner(); + ui_runner = thread_host_.ui_thread->GetTaskRunner(); + io_runner = thread_host_.io_thread->GetTaskRunner(); + } blink::TaskRunners task_runners( thread_label, // label - fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform - thread_host_.gpu_thread->GetTaskRunner(), // gpu - thread_host_.ui_thread->GetTaskRunner(), // ui - thread_host_.io_thread->GetTaskRunner() // io + platform_runner, // platform + gpu_runner, // gpu + ui_runner, // ui + io_runner // io ); shell_ = @@ -131,10 +162,12 @@ void AndroidShellHolder::Launch(RunConfiguration config) { fxl::MakeCopyable([engine = shell_->GetEngine(), // config = std::move(config) // ]() mutable { - if (engine) { - if (!engine->Run(std::move(config))) { - FXL_LOG(ERROR) << "Could not launch engine in configuration."; - } + FML_LOG(INFO) << "Attempting to launch engine configuration..."; + if (!engine || !engine->Run(std::move(config))) { + FML_LOG(ERROR) << "Could not launch engine in configuration."; + } else { + FML_LOG(INFO) << "Isolate for engine configuration successfully " + "started and run."; } })); } diff --git a/shell/platform/android/android_shell_holder.h b/shell/platform/android/android_shell_holder.h index 0163d4bbdc1d0..f16afc5b5b0af 100644 --- a/shell/platform/android/android_shell_holder.h +++ b/shell/platform/android/android_shell_holder.h @@ -21,7 +21,8 @@ namespace shell { class AndroidShellHolder { public: AndroidShellHolder(blink::Settings settings, - fml::jni::JavaObjectWeakGlobalRef java_object); + fml::jni::JavaObjectWeakGlobalRef java_object, + bool is_background_view); ~AndroidShellHolder(); diff --git a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java index 3d06d7f8505b5..5c5c367723272 100644 --- a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java +++ b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java @@ -30,6 +30,7 @@ import io.flutter.util.Preconditions; import io.flutter.view.FlutterMain; import io.flutter.view.FlutterNativeView; +import io.flutter.view.FlutterRunArguments; import io.flutter.view.FlutterView; import java.util.ArrayList; @@ -162,19 +163,16 @@ public void onCreate(Bundle savedInstanceState) { } } - // When an activity is created for the first time, we direct the - // FlutterView to re-use a pre-existing Isolate rather than create a new - // one. This is so that an Isolate coming in from the ViewFactory is - // used. - final boolean reuseIsolate = true; - - if (loadIntent(activity.getIntent(), reuseIsolate)) { + if (loadIntent(activity.getIntent())) { return; } if (!flutterView.getFlutterNativeView().isApplicationRunning()) { String appBundlePath = FlutterMain.findAppBundlePath(activity.getApplicationContext()); if (appBundlePath != null) { - flutterView.runFromBundle(appBundlePath, null, "main", reuseIsolate); + FlutterRunArguments arguments = new FlutterRunArguments(); + arguments.bundlePath = appBundlePath; + arguments.entrypoint = "main"; + flutterView.runFromBundle(arguments); } } } @@ -325,11 +323,6 @@ private static String[] getArgsFromIntent(Intent intent) { } private boolean loadIntent(Intent intent) { - final boolean reuseIsolate = false; - return loadIntent(intent, reuseIsolate); - } - - private boolean loadIntent(Intent intent, boolean reuseIsolate) { String action = intent.getAction(); if (Intent.ACTION_RUN.equals(action)) { String route = intent.getStringExtra("route"); @@ -343,7 +336,10 @@ private boolean loadIntent(Intent intent, boolean reuseIsolate) { flutterView.setInitialRoute(route); } if (!flutterView.getFlutterNativeView().isApplicationRunning()) { - flutterView.runFromBundle(appBundlePath, null, "main", reuseIsolate); + FlutterRunArguments args = new FlutterRunArguments(); + args.bundlePath = appBundlePath; + args.entrypoint = "main"; + flutterView.runFromBundle(args); } return true; } diff --git a/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java b/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java new file mode 100644 index 0000000000000..20006dd60547c --- /dev/null +++ b/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java @@ -0,0 +1,34 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.view; + +/** + * A class representing information for a callback registered using + * `PluginUtilities` from `dart:ui`. + */ +public final class FlutterCallbackInformation { + final public String callbackName; + final public String callbackClassName; + final public String callbackLibraryPath; + + /** + * Get callback information for a given handle. + * @param handle the handle for the callback, generated by + * `PluginUtilities.getCallbackHandle` in `dart:ui`. + * @return an instance of FlutterCallbackInformation for the provided handle. + */ + public static FlutterCallbackInformation lookupCallbackInformation(long handle) { + return nativeLookupCallbackInformation(handle); + } + + private FlutterCallbackInformation(String callbackName, + String callbackClassName, String callbackLibraryPath) { + this.callbackName = callbackName; + this.callbackClassName = callbackClassName; + this.callbackLibraryPath = callbackLibraryPath; + } + + private static native FlutterCallbackInformation nativeLookupCallbackInformation(long handle); +} diff --git a/shell/platform/android/io/flutter/view/FlutterNativeView.java b/shell/platform/android/io/flutter/view/FlutterNativeView.java index 46d8f5cb0d0d7..706183552fb0f 100644 --- a/shell/platform/android/io/flutter/view/FlutterNativeView.java +++ b/shell/platform/android/io/flutter/view/FlutterNativeView.java @@ -29,9 +29,13 @@ public class FlutterNativeView implements BinaryMessenger { private boolean applicationIsRunning; public FlutterNativeView(Context context) { + this(context, false); + } + + public FlutterNativeView(Context context, boolean isBackgroundView) { mContext = context; mPluginRegistry = new FlutterPluginRegistry(this, context); - attach(this); + attach(this, isBackgroundView); assertAttached(); mMessageHandlers = new HashMap<>(); } @@ -68,22 +72,43 @@ public long get() { } public void assertAttached() { - if (!isAttached()) - throw new AssertionError("Platform view is not attached"); + if (!isAttached()) throw new AssertionError("Platform view is not attached"); + } + + public void runFromBundle(FlutterRunArguments args) { + if (args.bundlePath == null) { + throw new AssertionError("A bundlePath must be specified"); + } else if (args.entrypoint == null) { + throw new AssertionError("An entrypoint must be specified"); + } + runFromBundleInternal(args.bundlePath, args.entrypoint, + args.libraryPath, null); + } + + /** + * @deprecated + * Please use runFromBundle with `FlutterRunArguments`. Parameters + * `snapshotOverride` and `reuseRuntimeController` have no effect. + */ + public void runFromBundle(String bundlePath, String snapshotOverride, String entrypoint, + boolean reuseRuntimeController) { + runFromBundleInternal(bundlePath, entrypoint, null, null); } - public void runFromBundle(String bundlePath, String snapshotOverride, String entrypoint, boolean reuseRuntimeController) { + private void runFromBundleInternal(String bundlePath, String entrypoint, + String libraryPath, String snapshotOverride) { assertAttached(); if (applicationIsRunning) - throw new AssertionError("This Flutter engine instance is already running an application"); - - nativeRunBundleAndSnapshot(mNativePlatformView, bundlePath, snapshotOverride, entrypoint, reuseRuntimeController, mContext.getResources().getAssets()); + throw new AssertionError( + "This Flutter engine instance is already running an application"); + nativeRunBundleAndSnapshotFromLibrary(mNativePlatformView, bundlePath, + entrypoint, libraryPath, mContext.getResources().getAssets()); applicationIsRunning = true; } public boolean isApplicationRunning() { - return applicationIsRunning; + return applicationIsRunning; } public static String getObservatoryUri() { @@ -92,7 +117,7 @@ public static String getObservatoryUri() { @Override public void send(String channel, ByteBuffer message) { - send(channel, message, null); + send(channel, message, null); } @Override @@ -110,8 +135,8 @@ public void send(String channel, ByteBuffer message, BinaryReply callback) { if (message == null) { nativeDispatchEmptyPlatformMessage(mNativePlatformView, channel, replyId); } else { - nativeDispatchPlatformMessage(mNativePlatformView, channel, message, - message.position(), replyId); + nativeDispatchPlatformMessage( + mNativePlatformView, channel, message, message.position(), replyId); } } @@ -124,8 +149,8 @@ public void setMessageHandler(String channel, BinaryMessageHandler handler) { } } - private void attach(FlutterNativeView view) { - mNativePlatformView = nativeAttach(view); + private void attach(FlutterNativeView view, boolean isBackgroundView) { + mNativePlatformView = nativeAttach(view, isBackgroundView); } // Called by native to send us a platform message. @@ -135,27 +160,28 @@ private void handlePlatformMessage(final String channel, byte[] message, final i if (handler != null) { try { final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message)); - handler.onMessage(buffer, - new BinaryReply() { - private final AtomicBoolean done = new AtomicBoolean(false); - @Override - public void reply(ByteBuffer reply) { - if (!isAttached()) { - Log.d(TAG, "handlePlatformMessage replying to a detached view, channel=" + channel); - return; - } - if (done.getAndSet(true)) { - throw new IllegalStateException("Reply already submitted"); - } - if (reply == null) { - nativeInvokePlatformMessageEmptyResponseCallback(mNativePlatformView, - replyId); - } else { - nativeInvokePlatformMessageResponseCallback(mNativePlatformView, - replyId, reply, reply.position()); - } + handler.onMessage(buffer, new BinaryReply() { + private final AtomicBoolean done = new AtomicBoolean(false); + @Override + public void reply(ByteBuffer reply) { + if (!isAttached()) { + Log.d(TAG, + "handlePlatformMessage replying to a detached view, channel=" + + channel); + return; + } + if (done.getAndSet(true)) { + throw new IllegalStateException("Reply already submitted"); } - }); + if (reply == null) { + nativeInvokePlatformMessageEmptyResponseCallback( + mNativePlatformView, replyId); + } else { + nativeInvokePlatformMessageResponseCallback( + mNativePlatformView, replyId, reply, reply.position()); + } + } + }); } catch (Exception ex) { Log.e(TAG, "Uncaught exception in binary message listener", ex); nativeInvokePlatformMessageEmptyResponseCallback(mNativePlatformView, replyId); @@ -179,8 +205,7 @@ private void handlePlatformMessageResponse(int replyId, byte[] reply) { // Called by native to update the semantics/accessibility tree. private void updateSemantics(ByteBuffer buffer, String[] strings) { - if (mFlutterView == null) - return; + if (mFlutterView == null) return; mFlutterView.updateSemantics(buffer, strings); } @@ -193,37 +218,33 @@ private void updateCustomAccessibilityActions(ByteBuffer buffer, String[] string // Called by native to notify first Flutter frame rendered. private void onFirstFrame() { - if (mFlutterView == null) - return; + if (mFlutterView == null) return; mFlutterView.onFirstFrame(); } - private static native long nativeAttach(FlutterNativeView view); + private static native long nativeAttach(FlutterNativeView view, boolean isBackgroundView); private static native void nativeDestroy(long nativePlatformViewAndroid); private static native void nativeDetach(long nativePlatformViewAndroid); - private static native void nativeRunBundleAndSnapshot(long nativePlatformViewAndroid, - String bundlePath, - String snapshotOverride, - String entrypoint, - boolean reuseRuntimeController, - AssetManager manager); + private static native void nativeRunBundleAndSnapshotFromLibrary( + long nativePlatformViewAndroid, String bundlePath, + String entrypoint, String libraryUrl, AssetManager manager); private static native String nativeGetObservatoryUri(); // Send an empty platform message to Dart. - private static native void nativeDispatchEmptyPlatformMessage(long nativePlatformViewAndroid, - String channel, int responseId); + private static native void nativeDispatchEmptyPlatformMessage( + long nativePlatformViewAndroid, String channel, int responseId); // Send a data-carrying platform message to Dart. private static native void nativeDispatchPlatformMessage(long nativePlatformViewAndroid, - String channel, ByteBuffer message, int position, int responseId); + String channel, ByteBuffer message, int position, int responseId); // Send an empty response to a platform message received from Dart. private static native void nativeInvokePlatformMessageEmptyResponseCallback( - long nativePlatformViewAndroid, int responseId); + long nativePlatformViewAndroid, int responseId); // Send a data-carrying response to a platform message received from Dart. private static native void nativeInvokePlatformMessageResponseCallback( - long nativePlatformViewAndroid, int responseId, ByteBuffer message, int position); + long nativePlatformViewAndroid, int responseId, ByteBuffer message, int position); } diff --git a/shell/platform/android/io/flutter/view/FlutterRunArguments.java b/shell/platform/android/io/flutter/view/FlutterRunArguments.java new file mode 100644 index 0000000000000..fb1218f57b168 --- /dev/null +++ b/shell/platform/android/io/flutter/view/FlutterRunArguments.java @@ -0,0 +1,16 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package io.flutter.view; + +/** + * A class containing arguments for entering a FlutterNativeView's isolate for + * the first time. + */ +public class FlutterRunArguments { + public String bundlePath; + public String entrypoint; + public String libraryPath; + public String snapshotOverride; +} diff --git a/shell/platform/android/io/flutter/view/FlutterView.java b/shell/platform/android/io/flutter/view/FlutterView.java index 8974a0bec5e10..8fe28670c123a 100644 --- a/shell/platform/android/io/flutter/view/FlutterView.java +++ b/shell/platform/android/io/flutter/view/FlutterView.java @@ -611,19 +611,41 @@ private void preRun() { private void postRun() { } + public void runFromBundle(FlutterRunArguments args) { + assertAttached(); + preRun(); + mNativeView.runFromBundle(args); + postRun(); + } + + /** + * @deprecated + * Please use runFromBundle with `FlutterRunArguments`. Parameter + * `snapshotOverride` has no effect. + */ public void runFromBundle(String bundlePath, String snapshotOverride) { runFromBundle(bundlePath, snapshotOverride, "main", false); } + /** + * @deprecated + * Please use runFromBundle with `FlutterRunArguments`. Parameter + * `snapshotOverride` has no effect. + */ public void runFromBundle(String bundlePath, String snapshotOverride, String entrypoint) { runFromBundle(bundlePath, snapshotOverride, entrypoint, false); } + /** + * @deprecated + * Please use runFromBundle with `FlutterRunArguments`. Parameters + * `snapshotOverride` and `reuseRuntimeController` have no effect. + */ public void runFromBundle(String bundlePath, String snapshotOverride, String entrypoint, boolean reuseRuntimeController) { - assertAttached(); - preRun(); - mNativeView.runFromBundle(bundlePath, snapshotOverride, entrypoint, reuseRuntimeController); - postRun(); + FlutterRunArguments args = new FlutterRunArguments(); + args.bundlePath = bundlePath; + args.entrypoint = entrypoint; + runFromBundle(args); } /** diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index 422358da27fcb..46513a556138d 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -30,21 +30,36 @@ PlatformViewAndroid::PlatformViewAndroid( "rendering."; } +PlatformViewAndroid::PlatformViewAndroid( + PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + fml::jni::JavaObjectWeakGlobalRef java_object) + : PlatformView(delegate, std::move(task_runners)), + java_object_(java_object), + android_surface_(nullptr) {} + PlatformViewAndroid::~PlatformViewAndroid() = default; void PlatformViewAndroid::NotifyCreated( fxl::RefPtr native_window) { - InstallFirstFrameCallback(); - android_surface_->SetNativeWindow(native_window); + if (android_surface_) { + InstallFirstFrameCallback(); + android_surface_->SetNativeWindow(native_window); + } PlatformView::NotifyCreated(); } void PlatformViewAndroid::NotifyDestroyed() { PlatformView::NotifyDestroyed(); - android_surface_->TeardownOnScreenContext(); + if (android_surface_) { + android_surface_->TeardownOnScreenContext(); + } } void PlatformViewAndroid::NotifyChanged(const SkISize& size) { + if (!android_surface_) { + return; + } fxl::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask( task_runners_.GetGPUTaskRunner(), // @@ -318,11 +333,17 @@ std::unique_ptr PlatformViewAndroid::CreateVSyncWaiter() { // |shell::PlatformView| std::unique_ptr PlatformViewAndroid::CreateRenderingSurface() { + if (!android_surface_) { + return nullptr; + } return android_surface_->CreateGPUSurface(); } // |shell::PlatformView| sk_sp PlatformViewAndroid::CreateResourceContext() const { + if (!android_surface_) { + return nullptr; + } sk_sp resource_context; if (android_surface_->ResourceContextMakeCurrent()) { // TODO(chinmaygarde): Currently, this code depends on the fact that only diff --git a/shell/platform/android/platform_view_android.h b/shell/platform/android/platform_view_android.h index b93a9834f3a25..8633c68388692 100644 --- a/shell/platform/android/platform_view_android.h +++ b/shell/platform/android/platform_view_android.h @@ -24,6 +24,13 @@ class PlatformViewAndroid final : public PlatformView { public: static bool Register(JNIEnv* env); + // Creates a PlatformViewAndroid with no rendering surface for use with + // background execution. + PlatformViewAndroid(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + fml::jni::JavaObjectWeakGlobalRef java_object); + + // Creates a PlatformViewAndroid with a rendering surface. PlatformViewAndroid(PlatformView::Delegate& delegate, blink::TaskRunners task_runners, fml::jni::JavaObjectWeakGlobalRef java_object, diff --git a/shell/platform/android/platform_view_android_jni.cc b/shell/platform/android/platform_view_android_jni.cc index 0fe2af1c5058e..1b530fb08c466 100644 --- a/shell/platform/android/platform_view_android_jni.cc +++ b/shell/platform/android/platform_view_android_jni.cc @@ -15,6 +15,7 @@ #include "flutter/fml/platform/android/jni_util.h" #include "flutter/fml/platform/android/jni_weak_ref.h" #include "flutter/fml/platform/android/scoped_java_ref.h" +#include "flutter/lib/ui/plugins/callback_cache.h" #include "flutter/runtime/dart_service_isolate.h" #include "flutter/shell/common/run_configuration.h" #include "flutter/shell/platform/android/android_external_texture_gl.h" @@ -43,6 +44,8 @@ bool CheckException(JNIEnv* env) { } // anonymous namespace +static fml::jni::ScopedJavaGlobalRef* g_flutter_callback_info_class = + nullptr; static fml::jni::ScopedJavaGlobalRef* g_flutter_view_class = nullptr; static fml::jni::ScopedJavaGlobalRef* g_flutter_native_view_class = nullptr; @@ -50,6 +53,19 @@ static fml::jni::ScopedJavaGlobalRef* g_surface_texture_class = nullptr; // Called By Native +static jmethodID g_flutter_callback_info_constructor = nullptr; +jobject CreateFlutterCallbackInformation( + JNIEnv* env, + const std::string& callbackName, + const std::string& callbackClassName, + const std::string& callbackLibraryPath) { + return env->NewObject(g_flutter_callback_info_class->obj(), + g_flutter_callback_info_constructor, + env->NewStringUTF(callbackName.c_str()), + env->NewStringUTF(callbackClassName.c_str()), + env->NewStringUTF(callbackLibraryPath.c_str())); +} + static jmethodID g_handle_platform_message_method = nullptr; void FlutterViewHandlePlatformMessage(JNIEnv* env, jobject obj, @@ -123,10 +139,13 @@ void SurfaceTextureDetachFromGLContext(JNIEnv* env, jobject obj) { // Called By Java -static jlong Attach(JNIEnv* env, jclass clazz, jobject flutterView) { +static jlong Attach(JNIEnv* env, + jclass clazz, + jobject flutterView, + jboolean is_background_view) { fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterView); auto shell_holder = std::make_unique( - FlutterMain::Get().GetSettings(), java_object); + FlutterMain::Get().GetSettings(), java_object, is_background_view); if (shell_holder->IsValid()) { return reinterpret_cast(shell_holder.release()); } else { @@ -202,14 +221,13 @@ std::unique_ptr CreateIsolateConfiguration( return nullptr; } -static void RunBundleAndSnapshot( +static void RunBundleAndSnapshotFromLibrary( JNIEnv* env, jobject jcaller, jlong shell_holder, jstring jbundlepath, - jstring /* snapshot override (unused) */, jstring jEntrypoint, - jboolean /* reuse runtime controller (unused) */, + jstring jLibraryUrl, jobject jAssetManager) { auto asset_manager = fml::MakeRefCounted(); @@ -255,7 +273,12 @@ static void RunBundleAndSnapshot( { auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint); - if (entrypoint.size() > 0) { + auto libraryUrl = fml::jni::JavaStringToString(env, jLibraryUrl); + + if ((entrypoint.size() > 0) && (libraryUrl.size() > 0)) { + config.SetEntrypointAndLibrary(std::move(entrypoint), + std::move(libraryUrl)); + } else if (entrypoint.size() > 0) { config.SetEntrypoint(std::move(entrypoint)); } } @@ -263,6 +286,15 @@ static void RunBundleAndSnapshot( ANDROID_SHELL_HOLDER->Launch(std::move(config)); } +static jobject LookupCallbackInformation(JNIEnv* env, /* unused */ jobject, jlong handle) { + auto cbInfo = blink::DartCallbackCache::GetCallbackInformation(handle); + if (cbInfo == nullptr) { + return nullptr; + } + return CreateFlutterCallbackInformation(env, cbInfo->name, cbInfo->class_name, + cbInfo->library_path); +} + static void SetViewportMetrics(JNIEnv* env, jobject jcaller, jlong shell_holder, @@ -489,6 +521,19 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { return false; } + g_flutter_callback_info_class = new fml::jni::ScopedJavaGlobalRef( + env, env->FindClass("io/flutter/view/FlutterCallbackInformation")); + if (g_flutter_callback_info_class->is_null()) { + return false; + } + + g_flutter_callback_info_constructor = env->GetMethodID( + g_flutter_callback_info_class->obj(), "", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + if (g_flutter_callback_info_constructor == nullptr) { + return false; + } + g_flutter_view_class = new fml::jni::ScopedJavaGlobalRef( env, env->FindClass("io/flutter/view/FlutterView")); if (g_flutter_view_class->is_null()) { @@ -510,7 +555,7 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { static const JNINativeMethod native_view_methods[] = { { .name = "nativeAttach", - .signature = "(Lio/flutter/view/FlutterNativeView;)J", + .signature = "(Lio/flutter/view/FlutterNativeView;Z)J", .fnPtr = reinterpret_cast(&shell::Attach), }, { @@ -519,10 +564,11 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { .fnPtr = reinterpret_cast(&shell::Destroy), }, { - .name = "nativeRunBundleAndSnapshot", - .signature = "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/" - "String;ZLandroid/content/res/AssetManager;)V", - .fnPtr = reinterpret_cast(&shell::RunBundleAndSnapshot), + .name = "nativeRunBundleAndSnapshotFromLibrary", + .signature = "(JLjava/lang/String;Ljava/lang/String;" + "Ljava/lang/String;Landroid/content/res/AssetManager;)V", + .fnPtr = + reinterpret_cast(&shell::RunBundleAndSnapshotFromLibrary), }, { .name = "nativeDetach", @@ -622,6 +668,14 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { }, }; + static const JNINativeMethod callback_info_methods[] = { + { + .name = "nativeLookupCallbackInformation", + .signature = "(J)Lio/flutter/view/FlutterCallbackInformation;", + .fnPtr = reinterpret_cast(&shell::LookupCallbackInformation), + }, + }; + if (env->RegisterNatives(g_flutter_native_view_class->obj(), native_view_methods, arraysize(native_view_methods)) != 0) { @@ -633,6 +687,12 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { return false; } + if (env->RegisterNatives(g_flutter_callback_info_class->obj(), + callback_info_methods, + arraysize(callback_info_methods)) != 0) { + return false; + } + g_handle_platform_message_method = env->GetMethodID(g_flutter_native_view_class->obj(), "handlePlatformMessage", "(Ljava/lang/String;[BI)V"); diff --git a/tools/licenses/pubspec.lock b/tools/licenses/pubspec.lock index 75d0f144fde64..c6c3b579591c0 100644 --- a/tools/licenses/pubspec.lock +++ b/tools/licenses/pubspec.lock @@ -1,53 +1,61 @@ # Generated by pub -# See http://pub.dartlang.org/doc/glossary.html#lockfile +# See https://www.dartlang.org/tools/pub/glossary#lockfile packages: archive: + dependency: "direct main" description: name: archive url: "https://pub.dartlang.org" source: hosted version: "1.0.33" args: + dependency: "direct main" description: name: args url: "https://pub.dartlang.org" source: hosted version: "0.13.7" charcode: + dependency: transitive description: name: charcode url: "https://pub.dartlang.org" source: hosted version: "1.1.1" collection: + dependency: transitive description: name: collection url: "https://pub.dartlang.org" source: hosted version: "1.14.5" convert: + dependency: transitive description: name: convert url: "https://pub.dartlang.org" source: hosted version: "2.0.1" crypto: + dependency: "direct main" description: name: crypto url: "https://pub.dartlang.org" source: hosted version: "2.0.2+1" path: + dependency: "direct main" description: name: path url: "https://pub.dartlang.org" source: hosted version: "1.5.1" typed_data: + dependency: transitive description: name: typed_data url: "https://pub.dartlang.org" source: hosted version: "1.1.5" sdks: - dart: ">=1.21.0 <2.0.0" + dart: ">=1.21.0 <=2.0.0-edge.7f1f54edc2cbe5280217ad3c858dd3df515aa3eb" diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index 29035a43eb7ae..dc4a370f0d3bc 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -501,6 +501,8 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/Platfor FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewRegistry.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewRegistryImpl.java FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java +FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterCallbackInformation.java +FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterRunArguments.java FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterCallbackCache.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterPluginAppLifeCycleDelegate.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterCallbackCache.mm From 16236f263779d1bd709b37c20cdf08e4ad6c20a8 Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Mon, 6 Aug 2018 12:02:51 -0700 Subject: [PATCH 21/22] Fixed merge errors and formatting --- runtime/dart_isolate.cc | 42 --------------- .../platform/android/android_shell_holder.cc | 53 +++++++++---------- .../platform/android/platform_view_android.cc | 4 +- .../android/platform_view_android_jni.cc | 35 ++++++------ 4 files changed, 46 insertions(+), 88 deletions(-) diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc index 1503a3db01a25..8f083246eae55 100644 --- a/runtime/dart_isolate.cc +++ b/runtime/dart_isolate.cc @@ -532,48 +532,6 @@ bool DartIsolate::RunFromLibrary(const std::string& library_name, return true; } -FXL_WARN_UNUSED_RESULT -bool DartIsolate::RunFromLibrary(const std::string& library_name, - const std::string& entrypoint_name) { - TRACE_EVENT0("flutter", "DartIsolate::RunFromLibrary"); - if (phase_ != Phase::Ready) { - return false; - } - - tonic::DartState::Scope scope(this); - - Dart_Handle library = Dart_LookupLibrary(tonic::ToDart(library_name.c_str())); - if (tonic::LogIfError(library)) { - return false; - } - - Dart_Handle entrypoint = - Dart_GetClosure(library, tonic::ToDart(entrypoint_name.c_str())); - if (tonic::LogIfError(entrypoint)) { - return false; - } - - Dart_Handle isolate_lib = Dart_LookupLibrary(tonic::ToDart("dart:isolate")); - if (tonic::LogIfError(isolate_lib)) { - return false; - } - - Dart_Handle isolate_args[] = { - entrypoint, - Dart_Null(), - }; - - if (tonic::LogIfError(Dart_Invoke( - isolate_lib, tonic::ToDart("_startMainIsolate"), - sizeof(isolate_args) / sizeof(isolate_args[0]), isolate_args))) { - return false; - } - - phase_ = Phase::Running; - FXL_DLOG(INFO) << "New isolate is in the running state."; - return true; -} - bool DartIsolate::Shutdown() { TRACE_EVENT0("flutter", "DartIsolate::Shutdown"); // This call may be re-entrant since Dart_ShutdownIsolate can invoke the diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index 10c153167e2a1..581f4ce7876bb 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -57,7 +57,7 @@ AndroidShellHolder::AndroidShellHolder( shell, // delegate shell.GetTaskRunners(), // task runners java_object // java object handle for JNI interop - ); + ); } else { platform_view_android = std::make_unique( @@ -66,7 +66,7 @@ AndroidShellHolder::AndroidShellHolder( java_object, // java object handle for JNI interop shell.GetSettings() .enable_software_rendering // use software rendering - ); + ); } weak_platform_view = platform_view_android->GetWeakPtr(); return platform_view_android; @@ -79,10 +79,10 @@ AndroidShellHolder::AndroidShellHolder( // The current thread will be used as the platform thread. Ensure that the // message loop is initialized. fml::MessageLoop::EnsureInitializedForCurrentThread(); - fxl::RefPtr gpu_runner; - fxl::RefPtr ui_runner; - fxl::RefPtr io_runner; - fxl::RefPtr platform_runner = + fml::RefPtr gpu_runner; + fml::RefPtr ui_runner; + fml::RefPtr io_runner; + fml::RefPtr platform_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); if (is_background_view) { auto single_task_runner = thread_host_.ui_thread->GetTaskRunner(); @@ -94,20 +94,19 @@ AndroidShellHolder::AndroidShellHolder( ui_runner = thread_host_.ui_thread->GetTaskRunner(); io_runner = thread_host_.io_thread->GetTaskRunner(); } - blink::TaskRunners task_runners( - thread_label, // label - platform_runner, // platform - gpu_runner, // gpu - ui_runner, // ui - io_runner // io - ); + blink::TaskRunners task_runners(thread_label, // label + platform_runner, // platform + gpu_runner, // gpu + ui_runner, // ui + io_runner // io + ); shell_ = Shell::Create(task_runners, // task runners settings_, // settings on_create_platform_view, // platform view create callback on_create_rasterizer // rasterizer create callback - ); + ); platform_view_ = weak_platform_view; FML_DCHECK(platform_view_); @@ -158,18 +157,18 @@ void AndroidShellHolder::Launch(RunConfiguration config) { return; } - shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - fml::MakeCopyable([engine = shell_->GetEngine(), // - config = std::move(config) // + shell_->GetTaskRunners().GetUITaskRunner()->PostTask(fml::MakeCopyable([ + engine = shell_->GetEngine(), // + config = std::move(config) // ]() mutable { - FML_LOG(INFO) << "Attempting to launch engine configuration..."; - if (!engine || !engine->Run(std::move(config))) { - FML_LOG(ERROR) << "Could not launch engine in configuration."; - } else { - FML_LOG(INFO) << "Isolate for engine configuration successfully " - "started and run."; - } - })); + FML_LOG(INFO) << "Attempting to launch engine configuration..."; + if (!engine || !engine->Run(std::move(config))) { + FML_LOG(ERROR) << "Could not launch engine in configuration."; + } else { + FML_LOG(INFO) << "Isolate for engine configuration successfully " + "started and run."; + } + })); } void AndroidShellHolder::SetViewportMetrics( @@ -179,7 +178,7 @@ void AndroidShellHolder::SetViewportMetrics( } shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - [engine = shell_->GetEngine(), metrics]() { + [ engine = shell_->GetEngine(), metrics ]() { if (engine) { engine->SetViewportMetrics(metrics); } @@ -193,7 +192,7 @@ void AndroidShellHolder::DispatchPointerDataPacket( } shell_->GetTaskRunners().GetUITaskRunner()->PostTask(fml::MakeCopyable( - [engine = shell_->GetEngine(), packet = std::move(packet)] { + [ engine = shell_->GetEngine(), packet = std::move(packet) ] { if (engine) { engine->DispatchPointerDataPacket(*packet); } diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index 742ba2c75bb62..ccd6ccb0cafbe 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -41,7 +41,7 @@ PlatformViewAndroid::PlatformViewAndroid( PlatformViewAndroid::~PlatformViewAndroid() = default; void PlatformViewAndroid::NotifyCreated( - fxl::RefPtr native_window) { + fml::RefPtr native_window) { if (android_surface_) { InstallFirstFrameCallback(); android_surface_->SetNativeWindow(native_window); @@ -60,7 +60,7 @@ void PlatformViewAndroid::NotifyChanged(const SkISize& size) { if (!android_surface_) { return; } - fxl::AutoResetWaitableEvent latch; + fml::AutoResetWaitableEvent latch; fml::TaskRunner::RunNowOrPostTask( task_runners_.GetGPUTaskRunner(), // [&latch, surface = android_surface_.get(), size]() { diff --git a/shell/platform/android/platform_view_android_jni.cc b/shell/platform/android/platform_view_android_jni.cc index e73f7a1565a0e..13738cb69d09f 100644 --- a/shell/platform/android/platform_view_android_jni.cc +++ b/shell/platform/android/platform_view_android_jni.cc @@ -237,15 +237,14 @@ std::unique_ptr CreateIsolateConfiguration( return IsolateConfiguration::CreateForAppSnapshot(); } -static void RunBundleAndSnapshotFromLibrary( - JNIEnv* env, - jobject jcaller, - jlong shell_holder, - jstring jbundlepath, - jstring jsnapshotOverride, - jstring jEntrypoint, - jstring jLibraryUrl, - jobject jAssetManager) { +static void RunBundleAndSnapshotFromLibrary(JNIEnv* env, + jobject jcaller, + jlong shell_holder, + jstring jbundlepath, + jstring jsnapshotOverride, + jstring jEntrypoint, + jstring jLibraryUrl, + jobject jAssetManager) { auto asset_manager = fml::MakeRefCounted(); const auto bundlepath = fml::jni::JavaStringToString(env, jbundlepath); @@ -272,7 +271,7 @@ static void RunBundleAndSnapshotFromLibrary( env, // jni environment jAssetManager, // asset manager std::move(apk_asset_dir)) // apk asset dir - ); + ); } } @@ -307,7 +306,9 @@ static void RunBundleAndSnapshotFromLibrary( ANDROID_SHELL_HOLDER->Launch(std::move(config)); } -static jobject LookupCallbackInformation(JNIEnv* env, /* unused */ jobject, jlong handle) { +static jobject LookupCallbackInformation(JNIEnv* env, + /* unused */ jobject, + jlong handle) { auto cbInfo = blink::DartCallbackCache::GetCallbackInformation(handle); if (cbInfo == nullptr) { return nullptr; @@ -434,7 +435,7 @@ static void DispatchPlatformMessage(JNIEnv* env, message, // position, // responseId // - ); + ); } static void DispatchEmptyPlatformMessage(JNIEnv* env, @@ -446,7 +447,7 @@ static void DispatchEmptyPlatformMessage(JNIEnv* env, env, // fml::jni::JavaStringToString(env, channel), // responseId // - ); + ); } static void DispatchPointerDataPacket(JNIEnv* env, @@ -472,7 +473,7 @@ static void DispatchSemanticsAction(JNIEnv* env, action, // args, // args_position // - ); + ); } static void SetSemanticsEnabled(JNIEnv* env, @@ -501,7 +502,7 @@ static void RegisterTexture(JNIEnv* env, ANDROID_SHELL_HOLDER->GetPlatformView()->RegisterExternalTexture( static_cast(texture_id), // fml::jni::JavaObjectWeakGlobalRef(env, surface_texture) // - ); + ); } static void MarkTextureFrameAvailable(JNIEnv* env, @@ -531,7 +532,7 @@ static void InvokePlatformMessageResponseCallback(JNIEnv* env, responseId, // message, // position // - ); + ); } static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env, @@ -541,7 +542,7 @@ static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env, ANDROID_SHELL_HOLDER->GetPlatformView() ->InvokePlatformMessageEmptyResponseCallback(env, // responseId // - ); + ); } bool PlatformViewAndroid::Register(JNIEnv* env) { From f0daa8e2fed06687dfb365fd0a185cd1bb3371fb Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Mon, 6 Aug 2018 12:19:52 -0700 Subject: [PATCH 22/22] More formatting --- .../platform/android/android_shell_holder.cc | 34 +++++++++---------- .../android/platform_view_android_jni.cc | 14 ++++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index 581f4ce7876bb..83d495347122f 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -57,7 +57,7 @@ AndroidShellHolder::AndroidShellHolder( shell, // delegate shell.GetTaskRunners(), // task runners java_object // java object handle for JNI interop - ); + ); } else { platform_view_android = std::make_unique( @@ -66,7 +66,7 @@ AndroidShellHolder::AndroidShellHolder( java_object, // java object handle for JNI interop shell.GetSettings() .enable_software_rendering // use software rendering - ); + ); } weak_platform_view = platform_view_android->GetWeakPtr(); return platform_view_android; @@ -99,14 +99,14 @@ AndroidShellHolder::AndroidShellHolder( gpu_runner, // gpu ui_runner, // ui io_runner // io - ); + ); shell_ = Shell::Create(task_runners, // task runners settings_, // settings on_create_platform_view, // platform view create callback on_create_rasterizer // rasterizer create callback - ); + ); platform_view_ = weak_platform_view; FML_DCHECK(platform_view_); @@ -157,18 +157,18 @@ void AndroidShellHolder::Launch(RunConfiguration config) { return; } - shell_->GetTaskRunners().GetUITaskRunner()->PostTask(fml::MakeCopyable([ - engine = shell_->GetEngine(), // - config = std::move(config) // + shell_->GetTaskRunners().GetUITaskRunner()->PostTask( + fml::MakeCopyable([engine = shell_->GetEngine(), // + config = std::move(config) // ]() mutable { - FML_LOG(INFO) << "Attempting to launch engine configuration..."; - if (!engine || !engine->Run(std::move(config))) { - FML_LOG(ERROR) << "Could not launch engine in configuration."; - } else { - FML_LOG(INFO) << "Isolate for engine configuration successfully " - "started and run."; - } - })); + FML_LOG(INFO) << "Attempting to launch engine configuration..."; + if (!engine || !engine->Run(std::move(config))) { + FML_LOG(ERROR) << "Could not launch engine in configuration."; + } else { + FML_LOG(INFO) << "Isolate for engine configuration successfully " + "started and run."; + } + })); } void AndroidShellHolder::SetViewportMetrics( @@ -178,7 +178,7 @@ void AndroidShellHolder::SetViewportMetrics( } shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - [ engine = shell_->GetEngine(), metrics ]() { + [engine = shell_->GetEngine(), metrics]() { if (engine) { engine->SetViewportMetrics(metrics); } @@ -192,7 +192,7 @@ void AndroidShellHolder::DispatchPointerDataPacket( } shell_->GetTaskRunners().GetUITaskRunner()->PostTask(fml::MakeCopyable( - [ engine = shell_->GetEngine(), packet = std::move(packet) ] { + [engine = shell_->GetEngine(), packet = std::move(packet)] { if (engine) { engine->DispatchPointerDataPacket(*packet); } diff --git a/shell/platform/android/platform_view_android_jni.cc b/shell/platform/android/platform_view_android_jni.cc index 13738cb69d09f..8bbab7753eea3 100644 --- a/shell/platform/android/platform_view_android_jni.cc +++ b/shell/platform/android/platform_view_android_jni.cc @@ -271,7 +271,7 @@ static void RunBundleAndSnapshotFromLibrary(JNIEnv* env, env, // jni environment jAssetManager, // asset manager std::move(apk_asset_dir)) // apk asset dir - ); + ); } } @@ -435,7 +435,7 @@ static void DispatchPlatformMessage(JNIEnv* env, message, // position, // responseId // - ); + ); } static void DispatchEmptyPlatformMessage(JNIEnv* env, @@ -447,7 +447,7 @@ static void DispatchEmptyPlatformMessage(JNIEnv* env, env, // fml::jni::JavaStringToString(env, channel), // responseId // - ); + ); } static void DispatchPointerDataPacket(JNIEnv* env, @@ -473,7 +473,7 @@ static void DispatchSemanticsAction(JNIEnv* env, action, // args, // args_position // - ); + ); } static void SetSemanticsEnabled(JNIEnv* env, @@ -502,7 +502,7 @@ static void RegisterTexture(JNIEnv* env, ANDROID_SHELL_HOLDER->GetPlatformView()->RegisterExternalTexture( static_cast(texture_id), // fml::jni::JavaObjectWeakGlobalRef(env, surface_texture) // - ); + ); } static void MarkTextureFrameAvailable(JNIEnv* env, @@ -532,7 +532,7 @@ static void InvokePlatformMessageResponseCallback(JNIEnv* env, responseId, // message, // position // - ); + ); } static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env, @@ -542,7 +542,7 @@ static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env, ANDROID_SHELL_HOLDER->GetPlatformView() ->InvokePlatformMessageEmptyResponseCallback(env, // responseId // - ); + ); } bool PlatformViewAndroid::Register(JNIEnv* env) {