From 871246172d5248c0b7985039b040b823f38b5861 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 16 Dec 2019 11:42:13 -0800 Subject: [PATCH] Allow custom embedders to post low memory notifications. (#14506) This is a non-breaking addition to the stable Flutter Embedder API. --- shell/platform/embedder/embedder.cc | 78 ++++++++++++++----- shell/platform/embedder/embedder.h | 23 +++++- .../embedder/tests/embedder_unittests.cc | 18 +++++ 3 files changed, 97 insertions(+), 22 deletions(-) diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index bbde2d6c5..6b45e0b8e 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -1503,6 +1503,37 @@ FlutterEngineResult FlutterEngineRunTask(FLUTTER_API_SYMBOL(FlutterEngine) "Could not run the specified task."); } +static bool DispatchJSONPlatformMessage(FLUTTER_API_SYMBOL(FlutterEngine) + engine, + rapidjson::Document document, + const std::string& channel_name) { + if (channel_name.size() == 0) { + return false; + } + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + + if (!document.Accept(writer)) { + return false; + } + + const char* message = buffer.GetString(); + + if (message == nullptr || buffer.GetSize() == 0) { + return false; + } + + auto platform_message = fml::MakeRefCounted( + channel_name.c_str(), // channel + std::vector{message, message + buffer.GetSize()}, // message + nullptr // response + ); + + return reinterpret_cast(engine) + ->SendPlatformMessage(std::move(platform_message)); +} + FlutterEngineResult FlutterEngineUpdateLocales(FLUTTER_API_SYMBOL(FlutterEngine) engine, const FlutterLocale** locales, @@ -1555,27 +1586,8 @@ FlutterEngineResult FlutterEngineUpdateLocales(FLUTTER_API_SYMBOL(FlutterEngine) } document.AddMember("args", args, allocator); - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - if (!document.Accept(writer)) { - return LOG_EMBEDDER_ERROR(kInternalInconsistency, - "Could not create locale payload."); - } - - const char* message = buffer.GetString(); - - if (message == nullptr || buffer.GetSize() == 0) { - return LOG_EMBEDDER_ERROR(kInternalInconsistency, - "Could not create locale update message."); - } - - auto platform_message = fml::MakeRefCounted( - "flutter/localization", // channel - std::vector{message, message + buffer.GetSize()}, // message - nullptr // response - ); - return reinterpret_cast(engine) - ->SendPlatformMessage(std::move(platform_message)) + return DispatchJSONPlatformMessage(engine, std::move(document), + "flutter/localization") ? kSuccess : LOG_EMBEDDER_ERROR(kInternalInconsistency, "Could not send message to update locale of " @@ -1710,3 +1722,27 @@ FlutterEngineResult FlutterEnginePostDartObject( typed_data_finalizer.Release(); return kSuccess; } + +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineNotifyLowMemoryWarning( + FLUTTER_API_SYMBOL(FlutterEngine) raw_engine) { + auto engine = reinterpret_cast(raw_engine); + if (engine == nullptr || !engine->IsValid()) { + return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine was invalid."); + } + + engine->GetShell().NotifyLowMemoryWarning(); + + rapidjson::Document document; + auto& allocator = document.GetAllocator(); + + document.SetObject(); + document.AddMember("type", "memoryPressure", allocator); + + return DispatchJSONPlatformMessage(raw_engine, std::move(document), + "flutter/system") + ? kSuccess + : LOG_EMBEDDER_ERROR( + kInternalInconsistency, + "Could not dispatch the low memory notification message."); +} diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index 5c11b403a..796d9bc90 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -1626,7 +1626,7 @@ bool FlutterEngineRunsAOTCompiledDartCode(void); /// `FlutterEngineDeinitialize` or `FlutterEngineShutdown` on /// another thread. /// -/// @param[in] engine. A running engine instance. +/// @param[in] engine A running engine instance. /// @param[in] port The send port to send the object to. /// @param[in] object The object to send to the isolate with the /// corresponding receive port. @@ -1639,6 +1639,27 @@ FlutterEngineResult FlutterEnginePostDartObject( FlutterEngineDartPort port, const FlutterEngineDartObject* object); +//------------------------------------------------------------------------------ +/// @brief Posts a low memory notification to a running engine instance. +/// The engine will do its best to release non-critical resources in +/// response. It is not guaranteed that the resource would have been +/// collected by the time this call returns however. The +/// notification is posted to engine subsystems that may be +/// operating on other threads. +/// +/// Flutter applications can respond to these notifications by +/// setting `WidgetsBindingObserver.didHaveMemoryPressure` +/// observers. +/// +/// @param[in] engine A running engine instance. +/// +/// @return If the low memory notification was sent to the running engine +/// instance. +/// +FLUTTER_EXPORT +FlutterEngineResult FlutterEngineNotifyLowMemoryWarning( + FLUTTER_API_SYMBOL(FlutterEngine) engine); + #if defined(__cplusplus) } // extern "C" #endif diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index 6a6256347..fe192ca00 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -3805,5 +3805,23 @@ TEST_F(EmbedderTest, ObjectsCanBePostedViaPorts) { buffer_released_latch.Wait(); } +TEST_F(EmbedderTest, CanSendLowMemoryNotification) { + auto& context = GetEmbedderContext(); + + EmbedderConfigBuilder builder(context); + builder.SetSoftwareRendererConfig(); + + auto engine = builder.LaunchEngine(); + + ASSERT_TRUE(engine.is_valid()); + + // TODO(chinmaygarde): The shell ought to have a mechanism for notification + // dispatch that engine subsystems can register handlers to. This would allow + // the raster cache and the secondary context caches to respond to + // notifications. Once that is in place, this test can be updated to actually + // ensure that the dispatched message is visible to engine subsystems. + ASSERT_EQ(FlutterEngineNotifyLowMemoryWarning(engine.get()), kSuccess); +} + } // namespace testing } // namespace flutter -- GitLab