diff --git a/DEPS b/DEPS index 864cc8b6ab0..a2a66bce119 100644 --- a/DEPS +++ b/DEPS @@ -145,7 +145,7 @@ deps = { # and not have to specific specific hashes. 'src/third_party/tonic': - Var('fuchsia_git') + '/tonic' + '@' + 'bd27b4549199df72fcaeefd259ebc12a31c2e4ee', + Var('fuchsia_git') + '/tonic' + '@' + '1a8ed9be2e2b56b32e888266d6db465d36012df4', 'src/third_party/benchmark': Var('fuchsia_git') + '/third_party/benchmark' + '@' + 'a779ffce872b4c811beef482e18bd0b63626aa42', diff --git a/engine/src/flutter/common/settings.h b/engine/src/flutter/common/settings.h index 2ebcbf0cd86..761b7734fbf 100644 --- a/engine/src/flutter/common/settings.h +++ b/engine/src/flutter/common/settings.h @@ -183,6 +183,14 @@ struct Settings { // soon as a frame is rasterized. FrameRasterizedCallback frame_rasterized_callback; + // This data will be available to the isolate immediately on launch via the + // Window.getPersistentIsolateData callback. This is meant for information + // that the isolate cannot request asynchronously (platform messages can be + // used for that purpose). This data is held for the lifetime of the shell and + // is available on isolate restarts in the the shell instance. Due to this, + // the buffer must be as small as possible. + std::shared_ptr persistent_isolate_data; + std::string ToString() const; }; diff --git a/engine/src/flutter/fml/mapping.cc b/engine/src/flutter/fml/mapping.cc index c349c5b30e0..d76efa799dc 100644 --- a/engine/src/flutter/fml/mapping.cc +++ b/engine/src/flutter/fml/mapping.cc @@ -4,6 +4,7 @@ #include "flutter/fml/mapping.h" +#include #include namespace fml { @@ -67,6 +68,9 @@ std::unique_ptr FileMapping::CreateReadExecute( DataMapping::DataMapping(std::vector data) : data_(std::move(data)) {} +DataMapping::DataMapping(const std::string& string) + : data_(string.begin(), string.end()) {} + DataMapping::~DataMapping() = default; size_t DataMapping::GetSize() const { diff --git a/engine/src/flutter/fml/mapping.h b/engine/src/flutter/fml/mapping.h index cd077bd4483..6cdcc2bae55 100644 --- a/engine/src/flutter/fml/mapping.h +++ b/engine/src/flutter/fml/mapping.h @@ -86,6 +86,8 @@ class DataMapping final : public Mapping { public: DataMapping(std::vector data); + DataMapping(const std::string& string); + ~DataMapping() override; // |Mapping| diff --git a/engine/src/flutter/lib/ui/window.dart b/engine/src/flutter/lib/ui/window.dart index a810551e382..3bd28a248bb 100644 --- a/engine/src/flutter/lib/ui/window.dart +++ b/engine/src/flutter/lib/ui/window.dart @@ -1176,6 +1176,18 @@ class Window { registrationZone.runUnaryGuarded(callback, data); }; } + + + /// The embedder can specify data that the isolate can request synchronously + /// on launch. This accessor fetches that data. + /// + /// This data is persistent for the duration of the Flutter application and is + /// available even after isolate restarts. Because of this lifecycle, the size + /// of this data must be kept to a minimum. + /// + /// For asynchronous communication between the embedder and isolate, a + /// platform channel may be used. + ByteData getPersistentIsolateData() native 'Window_getPersistentIsolateData'; } /// Additional accessibility features that may be enabled by the platform. diff --git a/engine/src/flutter/lib/ui/window/window.cc b/engine/src/flutter/lib/ui/window/window.cc index 7d3ab8ee5ec..5f5ae1dbe3d 100644 --- a/engine/src/flutter/lib/ui/window/window.cc +++ b/engine/src/flutter/lib/ui/window/window.cc @@ -142,6 +142,20 @@ void _RespondToPlatformMessage(Dart_NativeArguments args) { tonic::DartCallStatic(&RespondToPlatformMessage, args); } +void GetPersistentIsolateData(Dart_NativeArguments args) { + auto persistent_isolate_data = + UIDartState::Current()->window()->client()->GetPersistentIsolateData(); + + if (!persistent_isolate_data) { + Dart_SetReturnValue(args, Dart_Null()); + return; + } + + Dart_SetReturnValue( + args, tonic::DartByteData::Create(persistent_isolate_data->GetMapping(), + persistent_isolate_data->GetSize())); +} + } // namespace Dart_Handle ToByteData(const std::vector& buffer) { @@ -398,6 +412,7 @@ void Window::RegisterNatives(tonic::DartLibraryNatives* natives) { {"Window_setIsolateDebugName", SetIsolateDebugName, 2, true}, {"Window_reportUnhandledException", ReportUnhandledException, 2, true}, {"Window_setNeedsReportTimings", SetNeedsReportTimings, 2, true}, + {"Window_getPersistentIsolateData", GetPersistentIsolateData, 1, true}, }); } diff --git a/engine/src/flutter/lib/ui/window/window.h b/engine/src/flutter/lib/ui/window/window.h index 99a8585a691..bddcb70f315 100644 --- a/engine/src/flutter/lib/ui/window/window.h +++ b/engine/src/flutter/lib/ui/window/window.h @@ -57,6 +57,7 @@ class WindowClient { virtual void UpdateIsolateDescription(const std::string isolate_name, int64_t isolate_port) = 0; virtual void SetNeedsReportTimings(bool value) = 0; + virtual std::shared_ptr GetPersistentIsolateData() = 0; protected: virtual ~WindowClient(); diff --git a/engine/src/flutter/lib/web_ui/lib/src/ui/window.dart b/engine/src/flutter/lib/web_ui/lib/src/ui/window.dart index 80f15c712d1..47d27257be5 100644 --- a/engine/src/flutter/lib/web_ui/lib/src/ui/window.dart +++ b/engine/src/flutter/lib/web_ui/lib/src/ui/window.dart @@ -995,6 +995,8 @@ abstract class Window { String _initialLifecycleState; void setIsolateDebugName(String name) {} + + ByteData getPersistentIsolateData() => null; } VoidCallback webOnlyScheduleFrameCallback; diff --git a/engine/src/flutter/runtime/runtime_controller.cc b/engine/src/flutter/runtime/runtime_controller.cc index 7cc771ff8dd..61415ec4124 100644 --- a/engine/src/flutter/runtime/runtime_controller.cc +++ b/engine/src/flutter/runtime/runtime_controller.cc @@ -26,7 +26,8 @@ RuntimeController::RuntimeController( std::string p_advisory_script_entrypoint, std::function p_idle_notification_callback, fml::closure p_isolate_create_callback, - fml::closure p_isolate_shutdown_callback) + fml::closure p_isolate_shutdown_callback, + std::shared_ptr p_persistent_isolate_data) : RuntimeController(p_client, p_vm, std::move(p_isolate_snapshot), @@ -39,7 +40,8 @@ RuntimeController::RuntimeController( p_idle_notification_callback, WindowData{/* default window data */}, p_isolate_create_callback, - p_isolate_shutdown_callback) {} + p_isolate_shutdown_callback, + std::move(p_persistent_isolate_data)) {} RuntimeController::RuntimeController( RuntimeDelegate& p_client, @@ -54,7 +56,8 @@ RuntimeController::RuntimeController( std::function idle_notification_callback, WindowData p_window_data, fml::closure p_isolate_create_callback, - fml::closure p_isolate_shutdown_callback) + fml::closure p_isolate_shutdown_callback, + std::shared_ptr p_persistent_isolate_data) : client_(p_client), vm_(p_vm), isolate_snapshot_(std::move(p_isolate_snapshot)), @@ -67,7 +70,8 @@ RuntimeController::RuntimeController( idle_notification_callback_(idle_notification_callback), window_data_(std::move(p_window_data)), isolate_create_callback_(p_isolate_create_callback), - isolate_shutdown_callback_(p_isolate_shutdown_callback) { + isolate_shutdown_callback_(p_isolate_shutdown_callback), + persistent_isolate_data_(std::move(p_persistent_isolate_data)) { // Create the root isolate as soon as the runtime controller is initialized. // It will be run at a later point when the engine provides a run // configuration and then runs the isolate. @@ -144,7 +148,8 @@ std::unique_ptr RuntimeController::Clone() const { idle_notification_callback_, // window_data_, // isolate_create_callback_, // - isolate_shutdown_callback_ // + isolate_shutdown_callback_, // + persistent_isolate_data_ // )); } @@ -296,42 +301,56 @@ Window* RuntimeController::GetWindowIfAvailable() { return root_isolate ? root_isolate->window() : nullptr; } +// |WindowClient| std::string RuntimeController::DefaultRouteName() { return client_.DefaultRouteName(); } +// |WindowClient| void RuntimeController::ScheduleFrame() { client_.ScheduleFrame(); } +// |WindowClient| void RuntimeController::Render(Scene* scene) { client_.Render(scene->takeLayerTree()); } +// |WindowClient| void RuntimeController::UpdateSemantics(SemanticsUpdate* update) { if (window_data_.semantics_enabled) { client_.UpdateSemantics(update->takeNodes(), update->takeActions()); } } +// |WindowClient| void RuntimeController::HandlePlatformMessage( fml::RefPtr message) { client_.HandlePlatformMessage(std::move(message)); } +// |WindowClient| FontCollection& RuntimeController::GetFontCollection() { return client_.GetFontCollection(); } +// |WindowClient| void RuntimeController::UpdateIsolateDescription(const std::string isolate_name, int64_t isolate_port) { client_.UpdateIsolateDescription(isolate_name, isolate_port); } +// |WindowClient| void RuntimeController::SetNeedsReportTimings(bool value) { client_.SetNeedsReportTimings(value); } +// |WindowClient| +std::shared_ptr +RuntimeController::GetPersistentIsolateData() { + return persistent_isolate_data_; +} + Dart_Port RuntimeController::GetMainPort() { std::shared_ptr root_isolate = root_isolate_.lock(); return root_isolate ? root_isolate->main_port() : ILLEGAL_PORT; diff --git a/engine/src/flutter/runtime/runtime_controller.h b/engine/src/flutter/runtime/runtime_controller.h index 845bc45ef3b..665f0e17dbb 100644 --- a/engine/src/flutter/runtime/runtime_controller.h +++ b/engine/src/flutter/runtime/runtime_controller.h @@ -28,18 +28,20 @@ class Window; class RuntimeController final : public WindowClient { public: - RuntimeController(RuntimeDelegate& client, - DartVM* vm, - fml::RefPtr isolate_snapshot, - fml::RefPtr shared_snapshot, - TaskRunners task_runners, - fml::WeakPtr io_manager, - fml::WeakPtr iamge_decoder, - std::string advisory_script_uri, - std::string advisory_script_entrypoint, - std::function idle_notification_callback, - fml::closure isolate_create_callback, - fml::closure isolate_shutdown_callback); + RuntimeController( + RuntimeDelegate& client, + DartVM* vm, + fml::RefPtr isolate_snapshot, + fml::RefPtr shared_snapshot, + TaskRunners task_runners, + fml::WeakPtr io_manager, + fml::WeakPtr iamge_decoder, + std::string advisory_script_uri, + std::string advisory_script_entrypoint, + std::function idle_notification_callback, + fml::closure isolate_create_callback, + fml::closure isolate_shutdown_callback, + std::shared_ptr persistent_isolate_data); ~RuntimeController() override; @@ -138,20 +140,23 @@ class RuntimeController final : public WindowClient { std::pair root_isolate_return_code_ = {false, 0}; const fml::closure isolate_create_callback_; const fml::closure isolate_shutdown_callback_; + std::shared_ptr persistent_isolate_data_; - RuntimeController(RuntimeDelegate& client, - DartVM* vm, - fml::RefPtr isolate_snapshot, - fml::RefPtr shared_snapshot, - TaskRunners task_runners, - fml::WeakPtr io_manager, - fml::WeakPtr image_decoder, - std::string advisory_script_uri, - std::string advisory_script_entrypoint, - std::function idle_notification_callback, - WindowData data, - fml::closure isolate_create_callback, - fml::closure isolate_shutdown_callback); + RuntimeController( + RuntimeDelegate& client, + DartVM* vm, + fml::RefPtr isolate_snapshot, + fml::RefPtr shared_snapshot, + TaskRunners task_runners, + fml::WeakPtr io_manager, + fml::WeakPtr image_decoder, + std::string advisory_script_uri, + std::string advisory_script_entrypoint, + std::function idle_notification_callback, + WindowData data, + fml::closure isolate_create_callback, + fml::closure isolate_shutdown_callback, + std::shared_ptr persistent_isolate_data); Window* GetWindowIfAvailable(); @@ -182,6 +187,9 @@ class RuntimeController final : public WindowClient { // |WindowClient| void SetNeedsReportTimings(bool value) override; + // |WindowClient| + std::shared_ptr GetPersistentIsolateData() override; + FML_DISALLOW_COPY_AND_ASSIGN(RuntimeController); }; diff --git a/engine/src/flutter/shell/common/engine.cc b/engine/src/flutter/shell/common/engine.cc index f106c662daf..b3c889d6b1b 100644 --- a/engine/src/flutter/shell/common/engine.cc +++ b/engine/src/flutter/shell/common/engine.cc @@ -69,7 +69,8 @@ Engine::Engine(Delegate& delegate, settings_.advisory_script_entrypoint, // advisory script entrypoint settings_.idle_notification_callback, // idle notification callback settings_.isolate_create_callback, // isolate create callback - settings_.isolate_shutdown_callback // isolate shutdown callback + settings_.isolate_shutdown_callback, // isolate shutdown callback + settings_.persistent_isolate_data // persistent isolate data ); pointer_data_dispatcher_ = dispatcher_maker(*this); diff --git a/engine/src/flutter/shell/common/fixtures/shell_test.dart b/engine/src/flutter/shell/common/fixtures/shell_test.dart index 05f4782fc64..3c27d561e2c 100644 --- a/engine/src/flutter/shell/common/fixtures/shell_test.dart +++ b/engine/src/flutter/shell/common/fixtures/shell_test.dart @@ -110,3 +110,10 @@ void canCreateImageFromDecompressedData() { notifyWidthHeight(image.width, image.height); }); } + +@pragma('vm:entry-point') +void canAccessIsolateLaunchData() { + notifyMessage(utf8.decode(window.getPersistentIsolateData().buffer.asUint8List())); +} + +void notifyMessage(String string) native 'NotifyMessage'; diff --git a/engine/src/flutter/shell/common/shell_unittests.cc b/engine/src/flutter/shell/common/shell_unittests.cc index 1871f4ea081..bf9cbc4aea2 100644 --- a/engine/src/flutter/shell/common/shell_unittests.cc +++ b/engine/src/flutter/shell/common/shell_unittests.cc @@ -4,6 +4,7 @@ #define FML_USED_ON_EMBEDDER +#include #include #include #include @@ -873,5 +874,43 @@ TEST_F(ShellTest, TextureFrameMarkedAvailableAndUnregister) { EXPECT_EQ(mockTexture->unregistered(), true); } +TEST_F(ShellTest, IsolateCanAccessPersistentIsolateData) { + const std::string message = "dummy isolate launch data."; + + Settings settings = CreateSettingsForFixture(); + settings.persistent_isolate_data = + std::make_shared(message); + TaskRunners task_runners("test", // label + GetCurrentTaskRunner(), // platform + CreateNewThread(), // gpu + CreateNewThread(), // ui + CreateNewThread() // io + ); + + fml::AutoResetWaitableEvent message_latch; + AddNativeCallback("NotifyMessage", + CREATE_NATIVE_ENTRY([&](Dart_NativeArguments args) { + const auto message_from_dart = + tonic::DartConverter::FromDart( + Dart_GetNativeArgument(args, 0)); + ASSERT_EQ(message, message_from_dart); + message_latch.Signal(); + })); + + std::unique_ptr shell = + CreateShell(std::move(settings), std::move(task_runners)); + + ASSERT_TRUE(shell->IsSetup()); + auto configuration = RunConfiguration::InferFromSettings(settings); + configuration.SetEntrypoint("canAccessIsolateLaunchData"); + + fml::AutoResetWaitableEvent event; + shell->RunEngine(std::move(configuration), [&](auto result) { + ASSERT_EQ(result, Engine::RunStatus::Success); + }); + + message_latch.Wait(); +} + } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm index 53bb1b29e89..84fb859cbc4 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm @@ -7,6 +7,7 @@ #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" #include "flutter/common/task_runners.h" +#include "flutter/fml/mapping.h" #include "flutter/fml/message_loop.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/runtime/dart_vm.h" @@ -234,4 +235,22 @@ static flutter::Settings DefaultSettingsForProcess(NSBundle* bundle = nil) { return @"io.flutter.flutter.app"; } +#pragma mark - Settings utilities + +- (void)setPersistentIsolateData:(NSData*)data { + if (data == nil) { + return; + } + + NSData* persistent_isolate_data = [data copy]; + fml::NonOwnedMapping::ReleaseProc data_release_proc = [persistent_isolate_data](auto, auto) { + [persistent_isolate_data release]; + }; + _settings.persistent_isolate_data = std::make_shared( + static_cast(persistent_isolate_data.bytes), // bytes + persistent_isolate_data.length, // byte length + data_release_proc // release proc + ); +} + @end diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h index 22cee03e9c1..a93af57eaaa 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h @@ -22,6 +22,19 @@ NS_ASSUME_NONNULL_BEGIN + (NSString*)flutterAssetsName:(NSBundle*)bundle; +/** + * The embedder can specify data that the isolate can request synchronously on launch. Engines + * launched using this configuration can access the persistent isolate data via the + * `Window.getPersistentIsolateData` accessor. + * + * @param data The persistent isolate data. This data is persistent for the duration of the Flutter + * application and is available even after isolate restarts. Because of this lifecycle, + * the size of this data must be kept to a minimum and platform channels used for + * communication that does not require synchronous embedder to isolate communication + * close to isolate launch. + **/ +- (void)setPersistentIsolateData:(NSData*)data; + @end NS_ASSUME_NONNULL_END