Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions shell/common/platform_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

#include "flutter/fml/make_copyable.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/common/vsync_waiter_fallback.h"
#include "third_party/skia/include/gpu/gl/GrGLInterface.h"

Expand Down
2 changes: 0 additions & 2 deletions shell/common/platform_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@

namespace flutter {

class Shell;

//------------------------------------------------------------------------------
/// @brief Platform views are created by the shell on the platform task
/// runner. Unless explicitly specified, all platform view methods
Expand Down
9 changes: 9 additions & 0 deletions shell/platform/embedder/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,14 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
};
}

flutter::PlatformViewEmbedder::OnPreEngineRestartCallback
on_pre_engine_restart_callback = nullptr;
if (SAFE_ACCESS(args, on_pre_engine_restart_callback, nullptr) != nullptr) {
on_pre_engine_restart_callback = [ptr =
args->on_pre_engine_restart_callback,
user_data]() { return ptr(user_data); };
}

auto external_view_embedder_result =
InferExternalViewEmbedderFromArgs(SAFE_ACCESS(args, compositor, nullptr));
if (external_view_embedder_result.second) {
Expand All @@ -1182,6 +1190,7 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
platform_message_response_callback, //
vsync_callback, //
compute_platform_resolved_locale_callback, //
on_pre_engine_restart_callback, //
};

auto on_create_platform_view = InferPlatformViewCreationCallback(
Expand Down
11 changes: 11 additions & 0 deletions shell/platform/embedder/embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ typedef bool (*TextureFrameCallback)(void* /* user data */,
size_t /* height */,
FlutterOpenGLTexture* /* texture out */);
typedef void (*VsyncCallback)(void* /* user data */, intptr_t /* baton */);
typedef void (*OnPreEngineRestartCallback)(void* /* user data */);

/// A structure to represent the width and height.
typedef struct {
Expand Down Expand Up @@ -1577,6 +1578,16 @@ typedef struct {
// or component name to embedder's logger. This string will be passed to to
// callbacks on `log_message_callback`. Defaults to "flutter" if unspecified.
const char* log_tag;

// A callback that is invoked when the engine is restarted.
//
// This optional callback is typically used to reset states to as if the
// engine has just been started, and usually indicates the user has requested
// a hot restart (Shift-R in the Flutter CLI.) It is not called the first time
// the engine starts.
//
// The first argument is the `user_data` from `FlutterEngineInitialize`.
OnPreEngineRestartCallback on_pre_engine_restart_callback;
} FlutterProjectArgs;

#ifndef FLUTTER_ENGINE_NO_PROTOTYPES
Expand Down
7 changes: 7 additions & 0 deletions shell/platform/embedder/platform_view_embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,11 @@ PlatformViewEmbedder::ComputePlatformResolvedLocales(
return out;
}

// |PlatformView|
void PlatformViewEmbedder::OnPreEngineRestart() const {
if (platform_dispatch_table_.on_pre_engine_restart_callback != nullptr) {
platform_dispatch_table_.on_pre_engine_restart_callback();
}
}

} // namespace flutter
5 changes: 5 additions & 0 deletions shell/platform/embedder/platform_view_embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class PlatformViewEmbedder final : public PlatformView {
using ComputePlatformResolvedLocaleCallback =
std::function<std::unique_ptr<std::vector<std::string>>(
const std::vector<std::string>& supported_locale_data)>;
using OnPreEngineRestartCallback = std::function<void()>;

struct PlatformDispatchTable {
UpdateSemanticsNodesCallback update_semantics_nodes_callback; // optional
Expand All @@ -46,6 +47,7 @@ class PlatformViewEmbedder final : public PlatformView {
VsyncWaiterEmbedder::VsyncCallback vsync_callback; // optional
ComputePlatformResolvedLocaleCallback
compute_platform_resolved_locale_callback;
OnPreEngineRestartCallback on_pre_engine_restart_callback; // optional
};

// Create a platform view that sets up a software rasterizer.
Expand Down Expand Up @@ -104,6 +106,9 @@ class PlatformViewEmbedder final : public PlatformView {
// |PlatformView|
std::unique_ptr<VsyncWaiter> CreateVSyncWaiter() override;

// |PlatformView|
void OnPreEngineRestart() const override;

// |PlatformView|
std::unique_ptr<std::vector<std::string>> ComputePlatformResolvedLocales(
const std::vector<std::string>& supported_locale_data) override;
Expand Down
44 changes: 44 additions & 0 deletions shell/platform/linux/fl_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ struct _FlEngine {
FlEngineUpdateSemanticsNodeHandler update_semantics_node_handler;
gpointer update_semantics_node_handler_data;
GDestroyNotify update_semantics_node_handler_destroy_notify;

// Function to call when the engine is restarted.
FlEngineOnPreEngineRestartHandler on_pre_engine_restart_handler;
gpointer on_pre_engine_restart_handler_data;
GDestroyNotify on_pre_engine_restart_handler_destroy_notify;
};

G_DEFINE_QUARK(fl_engine_error_quark, fl_engine_error)
Expand Down Expand Up @@ -283,6 +288,20 @@ static void fl_engine_update_semantics_node_cb(const FlutterSemanticsNode* node,
}
}

// Called when the engine is restarted.
//
// This method should reset states to as if the engine has just been started,
// which usually indicates the user has requested a hot restart (Shift-R in the
// Flutter CLI.)
static void fl_engine_on_pre_engine_restart_cb(void* user_data) {
FlEngine* self = FL_ENGINE(user_data);

if (self->on_pre_engine_restart_handler != nullptr) {
self->on_pre_engine_restart_handler(
self, self->on_pre_engine_restart_handler_data);
}
}

// Called when a response to a sent platform message is received from the
// engine.
static void fl_engine_platform_message_response_cb(const uint8_t* data,
Expand Down Expand Up @@ -342,6 +361,13 @@ static void fl_engine_dispose(GObject* object) {
self->update_semantics_node_handler_data = nullptr;
self->update_semantics_node_handler_destroy_notify = nullptr;

if (self->on_pre_engine_restart_handler_destroy_notify) {
self->on_pre_engine_restart_handler_destroy_notify(
self->on_pre_engine_restart_handler_data);
}
self->on_pre_engine_restart_handler_data = nullptr;
self->on_pre_engine_restart_handler_destroy_notify = nullptr;

G_OBJECT_CLASS(fl_engine_parent_class)->dispose(object);
}

Expand Down Expand Up @@ -425,6 +451,7 @@ gboolean fl_engine_start(FlEngine* self, GError** error) {
args.update_semantics_node_callback = fl_engine_update_semantics_node_cb;
args.custom_task_runners = &custom_task_runners;
args.shutdown_dart_vm_when_done = true;
args.on_pre_engine_restart_callback = fl_engine_on_pre_engine_restart_cb;
args.dart_entrypoint_argc =
dart_entrypoint_args != nullptr ? g_strv_length(dart_entrypoint_args) : 0;
args.dart_entrypoint_argv =
Expand Down Expand Up @@ -519,6 +546,23 @@ void fl_engine_set_update_semantics_node_handler(
self->update_semantics_node_handler_destroy_notify = destroy_notify;
}

void fl_engine_set_on_pre_engine_restart_handler(
FlEngine* self,
FlEngineOnPreEngineRestartHandler handler,
gpointer user_data,
GDestroyNotify destroy_notify) {
g_return_if_fail(FL_IS_ENGINE(self));

if (self->on_pre_engine_restart_handler_destroy_notify) {
self->on_pre_engine_restart_handler_destroy_notify(
self->on_pre_engine_restart_handler_data);
}

self->on_pre_engine_restart_handler = handler;
self->on_pre_engine_restart_handler_data = user_data;
self->on_pre_engine_restart_handler_destroy_notify = destroy_notify;
}

gboolean fl_engine_send_platform_message_response(
FlEngine* self,
const FlutterPlatformMessageResponseHandle* handle,
Expand Down
26 changes: 26 additions & 0 deletions shell/platform/linux/fl_engine_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ typedef void (*FlEngineUpdateSemanticsNodeHandler)(
const FlutterSemanticsNode* node,
gpointer user_data);

/**
* FlEngineOnPreEngineRestartHandler:
* @engine: an #FlEngine.
* @user_data: semantic node information.
*
* @user_data: (closure): data provided when registering this handler.
*/
typedef void (*FlEngineOnPreEngineRestartHandler)(FlEngine* engine,
gpointer user_data);

/**
* fl_engine_new:
* @project: an #FlDartProject.
Expand Down Expand Up @@ -115,6 +125,22 @@ void fl_engine_set_update_semantics_node_handler(
gpointer user_data,
GDestroyNotify destroy_notify);

/**
* fl_engine_set_on_pre_engine_restart_handler:
* @engine: an #FlEngine.
* @handler: function to call when the engine is restarted.
* @user_data: (closure): user data to pass to @handler.
* @destroy_notify: (allow-none): a function which gets called to free
* @user_data, or %NULL.
*
* Registers the function called when the engine is restarted.
*/
void fl_engine_set_on_pre_engine_restart_handler(
FlEngine* engine,
FlEngineOnPreEngineRestartHandler handler,
gpointer user_data,
GDestroyNotify destroy_notify);

/**
* fl_engine_start:
* @engine: an #FlEngine.
Expand Down
56 changes: 56 additions & 0 deletions shell/platform/linux/fl_engine_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,62 @@ TEST(FlEngineTest, SettingsPlugin) {
EXPECT_TRUE(called);
}

void on_pre_engine_restart_cb(FlEngine* engine, gpointer user_data) {
int* count = reinterpret_cast<int*>(user_data);
*count += 1;
}

void on_pre_engine_restart_destroy_notify(gpointer user_data) {
int* count = reinterpret_cast<int*>(user_data);
*count += 10;
}

// Checks restarting the engine invokes the correct callback.
TEST(FlEngineTest, OnPreEngineRestart) {
g_autoptr(FlEngine) engine = make_mock_engine();
FlutterEngineProcTable* embedder_api = fl_engine_get_embedder_api(engine);

OnPreEngineRestartCallback callback;
void* callback_user_data;

bool called = false;
embedder_api->Initialize = MOCK_ENGINE_PROC(
Initialize, ([&callback, &callback_user_data, &called](
size_t version, const FlutterRendererConfig* config,
const FlutterProjectArgs* args, void* user_data,
FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
called = true;
callback = args->on_pre_engine_restart_callback;
callback_user_data = user_data;

return kSuccess;
}));

g_autoptr(GError) error = nullptr;
EXPECT_TRUE(fl_engine_start(engine, &error));
EXPECT_EQ(error, nullptr);

EXPECT_TRUE(called);
EXPECT_NE(callback, nullptr);

// The following call has no effect but should not crash.
callback(callback_user_data);

int count = 0;

// Set a handler, and the call should has an effect.
fl_engine_set_on_pre_engine_restart_handler(
engine, on_pre_engine_restart_cb, &count,
on_pre_engine_restart_destroy_notify);

callback(callback_user_data);
EXPECT_EQ(count, 1);

// Disposal should call the destroy notify.
g_object_unref(engine);
EXPECT_EQ(count, 11);
}

TEST(FlEngineTest, DartEntrypointArgs) {
g_autoptr(FlDartProject) project = fl_dart_project_new();

Expand Down