mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Reduce app startup latency by initializing the engine on a separate thread (#166918)
If settings.merged_platform_ui_thread is set to kMergeAfterLaunch, then the engine will be started on the UI thread. After engine setup completes and the Dart isolate is loaded, the UI task runner will be merged into the platform thread and all future Dart execution will run on the platform thread. This makes it possible for other work to run on the platform thread while the engine starts. See https://github.com/flutter/flutter/issues/163064
This commit is contained in:
parent
9f4fe843a7
commit
c53fdbdf24
@ -16,6 +16,7 @@
|
||||
#include "flutter/fml/build_config.h"
|
||||
#include "flutter/fml/closure.h"
|
||||
#include "flutter/fml/mapping.h"
|
||||
#include "flutter/fml/task_queue_id.h"
|
||||
#include "flutter/fml/time/time_point.h"
|
||||
#include "flutter/fml/unique_fd.h"
|
||||
|
||||
@ -70,8 +71,10 @@ class FrameTiming {
|
||||
};
|
||||
|
||||
using TaskObserverAdd =
|
||||
std::function<void(intptr_t /* key */, fml::closure /* callback */)>;
|
||||
using TaskObserverRemove = std::function<void(intptr_t /* key */)>;
|
||||
std::function<fml::TaskQueueId(intptr_t /* key */,
|
||||
fml::closure /* callback */)>;
|
||||
using TaskObserverRemove =
|
||||
std::function<void(fml::TaskQueueId /* queue */, intptr_t /* key */)>;
|
||||
using UnhandledExceptionCallback =
|
||||
std::function<bool(const std::string& /* error */,
|
||||
const std::string& /* stack trace */)>;
|
||||
@ -359,9 +362,20 @@ struct Settings {
|
||||
/// This is used by the runOnPlatformThread API.
|
||||
bool enable_platform_isolates = false;
|
||||
|
||||
// If true, the UI thread is the platform thread on supported
|
||||
// platforms.
|
||||
bool merged_platform_ui_thread = true;
|
||||
enum class MergedPlatformUIThread {
|
||||
// Use separate threads for the UI and platform task runners.
|
||||
kDisabled,
|
||||
// Use the platform thread for both the UI and platform task runners.
|
||||
kEnabled,
|
||||
// Start the engine on a separate UI thread and then move the UI task
|
||||
// runner to the platform thread after the engine is initialized.
|
||||
// This can improve app launch latency by allowing other work to run on
|
||||
// the platform thread during engine startup.
|
||||
kMergeAfterLaunch
|
||||
};
|
||||
|
||||
MergedPlatformUIThread merged_platform_ui_thread =
|
||||
MergedPlatformUIThread::kEnabled;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@ -16,14 +16,16 @@ void ExecuteAfterTaskObservers() {
|
||||
}
|
||||
}
|
||||
|
||||
void CurrentMessageLoopAddAfterTaskObserver(intptr_t key,
|
||||
fit::closure observer) {
|
||||
fml::TaskQueueId CurrentMessageLoopAddAfterTaskObserver(intptr_t key,
|
||||
fit::closure observer) {
|
||||
if (observer) {
|
||||
tTaskObservers[key] = std::move(observer);
|
||||
}
|
||||
return fml::TaskQueueId::Invalid();
|
||||
}
|
||||
|
||||
void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key) {
|
||||
void CurrentMessageLoopRemoveAfterTaskObserver(fml::TaskQueueId queue_id,
|
||||
intptr_t key) {
|
||||
tTaskObservers.erase(key);
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
|
||||
#include <lib/fit/function.h>
|
||||
|
||||
#include "flutter/fml/task_queue_id.h"
|
||||
|
||||
namespace fml {
|
||||
|
||||
// Executes all closures that were registered via
|
||||
@ -30,10 +32,11 @@ namespace fml {
|
||||
// somehow.
|
||||
void ExecuteAfterTaskObservers();
|
||||
|
||||
void CurrentMessageLoopAddAfterTaskObserver(intptr_t key,
|
||||
fit::closure observer);
|
||||
fml::TaskQueueId CurrentMessageLoopAddAfterTaskObserver(intptr_t key,
|
||||
fit::closure observer);
|
||||
|
||||
void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key);
|
||||
void CurrentMessageLoopRemoveAfterTaskObserver(fml::TaskQueueId queue_id,
|
||||
intptr_t key);
|
||||
|
||||
} // namespace fml
|
||||
|
||||
|
||||
@ -25,6 +25,8 @@ class TaskQueueId {
|
||||
/// Intializes a task queue with the given value as it's ID.
|
||||
explicit TaskQueueId(size_t value) : value_(value) {}
|
||||
|
||||
static TaskQueueId Invalid() { return TaskQueueId(kInvalid); }
|
||||
|
||||
operator size_t() const { // NOLINT(google-explicit-constructor)
|
||||
return value_;
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ ImageDecoder::ImageDecoder(
|
||||
|
||||
ImageDecoder::~ImageDecoder() = default;
|
||||
|
||||
fml::WeakPtr<ImageDecoder> ImageDecoder::GetWeakPtr() const {
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> ImageDecoder::GetWeakPtr() const {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
|
||||
@ -44,7 +44,7 @@ class ImageDecoder {
|
||||
uint32_t target_height,
|
||||
const ImageResult& result) = 0;
|
||||
|
||||
fml::WeakPtr<ImageDecoder> GetWeakPtr() const;
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> GetWeakPtr() const;
|
||||
|
||||
protected:
|
||||
TaskRunners runners_;
|
||||
@ -57,7 +57,7 @@ class ImageDecoder {
|
||||
fml::WeakPtr<IOManager> io_manager);
|
||||
|
||||
private:
|
||||
fml::WeakPtrFactory<ImageDecoder> weak_factory_;
|
||||
fml::TaskRunnerAffineWeakPtrFactory<ImageDecoder> weak_factory_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(ImageDecoder);
|
||||
};
|
||||
|
||||
@ -79,8 +79,8 @@ ImageGeneratorRegistry::CreateCompatibleGenerator(const sk_sp<SkData>& buffer) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fml::WeakPtr<ImageGeneratorRegistry> ImageGeneratorRegistry::GetWeakPtr()
|
||||
const {
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
ImageGeneratorRegistry::GetWeakPtr() const {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ class ImageGeneratorRegistry {
|
||||
std::shared_ptr<ImageGenerator> CreateCompatibleGenerator(
|
||||
const sk_sp<SkData>& buffer);
|
||||
|
||||
fml::WeakPtr<ImageGeneratorRegistry> GetWeakPtr() const;
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry> GetWeakPtr() const;
|
||||
|
||||
private:
|
||||
struct PrioritizedFactory {
|
||||
@ -85,7 +85,7 @@ class ImageGeneratorRegistry {
|
||||
using FactorySet = std::set<PrioritizedFactory, Compare>;
|
||||
FactorySet image_generator_factories_;
|
||||
size_t nonce_;
|
||||
fml::WeakPtrFactory<ImageGeneratorRegistry> weak_factory_;
|
||||
fml::TaskRunnerAffineWeakPtrFactory<ImageGeneratorRegistry> weak_factory_;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@ -24,8 +24,9 @@ UIDartState::Context::Context(
|
||||
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<IOManager> io_manager,
|
||||
fml::RefPtr<SkiaUnrefQueue> unref_queue,
|
||||
fml::WeakPtr<ImageDecoder> image_decoder,
|
||||
fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry,
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> image_decoder,
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
image_generator_registry,
|
||||
std::string advisory_script_uri,
|
||||
std::string advisory_script_entrypoint,
|
||||
bool deterministic_rendering_enabled,
|
||||
@ -58,6 +59,7 @@ UIDartState::UIDartState(
|
||||
const UIDartState::Context& context)
|
||||
: add_callback_(std::move(add_callback)),
|
||||
remove_callback_(std::move(remove_callback)),
|
||||
callback_queue_id_(fml::TaskQueueId::kInvalid),
|
||||
logger_prefix_(std::move(logger_prefix)),
|
||||
is_root_isolate_(is_root_isolate),
|
||||
unhandled_exception_callback_(std::move(unhandled_exception_callback)),
|
||||
@ -178,10 +180,12 @@ void UIDartState::AddOrRemoveTaskObserver(bool add) {
|
||||
}
|
||||
FML_DCHECK(add_callback_ && remove_callback_);
|
||||
if (add) {
|
||||
add_callback_(reinterpret_cast<intptr_t>(this),
|
||||
[this]() { this->FlushMicrotasksNow(); });
|
||||
callback_queue_id_ =
|
||||
add_callback_(reinterpret_cast<intptr_t>(this),
|
||||
[this]() { this->FlushMicrotasksNow(); });
|
||||
} else {
|
||||
remove_callback_(reinterpret_cast<intptr_t>(this));
|
||||
remove_callback_(callback_queue_id_, reinterpret_cast<intptr_t>(this));
|
||||
callback_queue_id_ = fml::TaskQueueId::Invalid();
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,12 +194,13 @@ UIDartState::GetSnapshotDelegate() const {
|
||||
return context_.snapshot_delegate;
|
||||
}
|
||||
|
||||
fml::WeakPtr<ImageDecoder> UIDartState::GetImageDecoder() const {
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> UIDartState::GetImageDecoder()
|
||||
const {
|
||||
return context_.image_decoder;
|
||||
}
|
||||
|
||||
fml::WeakPtr<ImageGeneratorRegistry> UIDartState::GetImageGeneratorRegistry()
|
||||
const {
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
UIDartState::GetImageGeneratorRegistry() const {
|
||||
return context_.image_generator_registry;
|
||||
}
|
||||
|
||||
|
||||
@ -48,8 +48,9 @@ class UIDartState : public tonic::DartState {
|
||||
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<IOManager> io_manager,
|
||||
fml::RefPtr<SkiaUnrefQueue> unref_queue,
|
||||
fml::WeakPtr<ImageDecoder> image_decoder,
|
||||
fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry,
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> image_decoder,
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
image_generator_registry,
|
||||
std::string advisory_script_uri,
|
||||
std::string advisory_script_entrypoint,
|
||||
bool deterministic_rendering_enabled,
|
||||
@ -76,12 +77,13 @@ class UIDartState : public tonic::DartState {
|
||||
fml::RefPtr<SkiaUnrefQueue> unref_queue;
|
||||
|
||||
/// The image decoder.
|
||||
fml::WeakPtr<ImageDecoder> image_decoder;
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> image_decoder;
|
||||
|
||||
/// Cascading registry of image generator builders. Given compressed image
|
||||
/// bytes as input, this is used to find and create image generators, which
|
||||
/// can then be used for image decoding.
|
||||
fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry;
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
image_generator_registry;
|
||||
|
||||
/// The advisory script URI (only used for debugging). This does not affect
|
||||
/// the code being run in the isolate in any way.
|
||||
@ -144,9 +146,10 @@ class UIDartState : public tonic::DartState {
|
||||
|
||||
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> GetSnapshotDelegate() const;
|
||||
|
||||
fml::WeakPtr<ImageDecoder> GetImageDecoder() const;
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> GetImageDecoder() const;
|
||||
|
||||
fml::WeakPtr<ImageGeneratorRegistry> GetImageGeneratorRegistry() const;
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
GetImageGeneratorRegistry() const;
|
||||
|
||||
std::shared_ptr<IsolateNameServer> GetIsolateNameServer() const;
|
||||
|
||||
@ -205,6 +208,7 @@ class UIDartState : public tonic::DartState {
|
||||
|
||||
const TaskObserverAdd add_callback_;
|
||||
const TaskObserverRemove remove_callback_;
|
||||
fml::TaskQueueId callback_queue_id_;
|
||||
const std::string logger_prefix_;
|
||||
Dart_Port main_port_ = ILLEGAL_PORT;
|
||||
const bool is_root_isolate_;
|
||||
|
||||
@ -155,7 +155,10 @@ std::weak_ptr<DartIsolate> DartIsolate::CreateRunningRootIsolate(
|
||||
|
||||
{
|
||||
tonic::DartState::Scope scope(isolate.get());
|
||||
Dart_SetCurrentThreadOwnsIsolate();
|
||||
if (settings.merged_platform_ui_thread !=
|
||||
Settings::MergedPlatformUIThread::kMergeAfterLaunch) {
|
||||
Dart_SetCurrentThreadOwnsIsolate();
|
||||
}
|
||||
|
||||
if (settings.root_isolate_create_callback) {
|
||||
// Isolate callbacks always occur in isolate scope and before user code
|
||||
@ -349,6 +352,7 @@ Dart_Isolate DartIsolate::CreatePlatformIsolate(Dart_Handle entry_point,
|
||||
}
|
||||
old_task_observer_add(key, callback);
|
||||
});
|
||||
return platform_task_runner->GetTaskQueueId();
|
||||
};
|
||||
|
||||
UIDartState::Context context(task_runners);
|
||||
@ -1373,6 +1377,11 @@ std::weak_ptr<DartIsolate> DartIsolate::GetWeakIsolatePtr() {
|
||||
return std::static_pointer_cast<DartIsolate>(shared_from_this());
|
||||
}
|
||||
|
||||
void DartIsolate::SetOwnerToCurrentThread() {
|
||||
tonic::DartIsolateScope isolate_scope(isolate());
|
||||
Dart_SetCurrentThreadOwnsIsolate();
|
||||
}
|
||||
|
||||
void DartIsolate::AddIsolateShutdownCallback(const fml::closure& closure) {
|
||||
shutdown_callbacks_.emplace_back(std::make_unique<AutoFireClosure>(closure));
|
||||
}
|
||||
|
||||
@ -411,6 +411,10 @@ class DartIsolate : public UIDartState {
|
||||
static Dart_Handle LoadLibraryFromKernel(
|
||||
const std::shared_ptr<const fml::Mapping>& mapping);
|
||||
|
||||
// Calls a Dart API that sets the isolate's owner thread to the current
|
||||
// thread.
|
||||
void SetOwnerToCurrentThread();
|
||||
|
||||
private:
|
||||
friend class IsolateConfiguration;
|
||||
class AutoFireClosure {
|
||||
|
||||
@ -56,8 +56,9 @@ std::unique_ptr<RuntimeController> RuntimeController::Spawn(
|
||||
const fml::closure& p_isolate_shutdown_callback,
|
||||
const std::shared_ptr<const fml::Mapping>& p_persistent_isolate_data,
|
||||
fml::WeakPtr<IOManager> io_manager,
|
||||
fml::WeakPtr<ImageDecoder> image_decoder,
|
||||
fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry,
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> image_decoder,
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
image_generator_registry,
|
||||
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate) const {
|
||||
UIDartState::Context spawned_context{context_.task_runners,
|
||||
std::move(snapshot_delegate),
|
||||
@ -676,6 +677,13 @@ void RuntimeController::ShutdownPlatformIsolates() {
|
||||
platform_isolate_manager_->ShutdownPlatformIsolates();
|
||||
}
|
||||
|
||||
void RuntimeController::SetRootIsolateOwnerToCurrentThread() {
|
||||
std::shared_ptr<DartIsolate> root_isolate = root_isolate_.lock();
|
||||
if (root_isolate) {
|
||||
root_isolate->SetOwnerToCurrentThread();
|
||||
}
|
||||
}
|
||||
|
||||
RuntimeController::Locale::Locale(std::string language_code_,
|
||||
std::string country_code_,
|
||||
std::string script_code_,
|
||||
|
||||
@ -121,8 +121,9 @@ class RuntimeController : public PlatformConfigurationClient,
|
||||
const fml::closure& isolate_shutdown_callback,
|
||||
const std::shared_ptr<const fml::Mapping>& persistent_isolate_data,
|
||||
fml::WeakPtr<IOManager> io_manager,
|
||||
fml::WeakPtr<ImageDecoder> image_decoder,
|
||||
fml::WeakPtr<ImageGeneratorRegistry> image_generator_registry,
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> image_decoder,
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
image_generator_registry,
|
||||
fml::TaskRunnerAffineWeakPtr<SnapshotDelegate> snapshot_delegate) const;
|
||||
|
||||
// |PlatformConfigurationClient|
|
||||
@ -678,6 +679,8 @@ class RuntimeController : public PlatformConfigurationClient,
|
||||
return platform_isolate_manager_;
|
||||
}
|
||||
|
||||
void SetRootIsolateOwnerToCurrentThread();
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
/// @brief Shuts down all registered platform isolates. Must be called
|
||||
/// from the platform thread.
|
||||
|
||||
@ -148,7 +148,7 @@ class Animator final {
|
||||
std::deque<uint64_t> trace_flow_ids_;
|
||||
bool has_rendered_ = false;
|
||||
|
||||
fml::WeakPtrFactory<Animator> weak_factory_;
|
||||
fml::TaskRunnerAffineWeakPtrFactory<Animator> weak_factory_;
|
||||
|
||||
friend class testing::ShellTest;
|
||||
|
||||
|
||||
@ -148,7 +148,7 @@ std::unique_ptr<Engine> Engine::Spawn(
|
||||
|
||||
Engine::~Engine() = default;
|
||||
|
||||
fml::WeakPtr<Engine> Engine::GetWeakPtr() const {
|
||||
fml::TaskRunnerAffineWeakPtr<Engine> Engine::GetWeakPtr() const {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
@ -161,11 +161,12 @@ std::shared_ptr<AssetManager> Engine::GetAssetManager() {
|
||||
return asset_manager_;
|
||||
}
|
||||
|
||||
fml::WeakPtr<ImageDecoder> Engine::GetImageDecoderWeakPtr() {
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> Engine::GetImageDecoderWeakPtr() {
|
||||
return image_decoder_->GetWeakPtr();
|
||||
}
|
||||
|
||||
fml::WeakPtr<ImageGeneratorRegistry> Engine::GetImageGeneratorRegistry() {
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
Engine::GetImageGeneratorRegistry() {
|
||||
return image_generator_registry_.GetWeakPtr();
|
||||
}
|
||||
|
||||
@ -239,6 +240,19 @@ Engine::RunStatus Engine::Run(RunConfiguration configuration) {
|
||||
}
|
||||
};
|
||||
|
||||
if (settings_.merged_platform_ui_thread ==
|
||||
Settings::MergedPlatformUIThread::kMergeAfterLaunch) {
|
||||
// Queue a task to the UI task runner that sets the owner of the root
|
||||
// isolate. This task runs after the thread merge and will therefore be
|
||||
// executed on the platform thread. The task will run before any tasks
|
||||
// queued by LaunchRootIsolate that execute the app's Dart code.
|
||||
task_runners_.GetUITaskRunner()->PostTask([engine = GetWeakPtr()]() {
|
||||
if (engine) {
|
||||
engine->runtime_controller_->SetRootIsolateOwnerToCurrentThread();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!runtime_controller_->LaunchRootIsolate(
|
||||
settings_, //
|
||||
root_isolate_create_callback, //
|
||||
@ -260,6 +274,18 @@ Engine::RunStatus Engine::Run(RunConfiguration configuration) {
|
||||
HandlePlatformMessage(std::move(service_id_message));
|
||||
}
|
||||
|
||||
if (settings_.merged_platform_ui_thread ==
|
||||
Settings::MergedPlatformUIThread::kMergeAfterLaunch) {
|
||||
// Move the UI task runner to the platform thread.
|
||||
bool success = fml::MessageLoopTaskQueues::GetInstance()->Merge(
|
||||
task_runners_.GetPlatformTaskRunner()->GetTaskQueueId(),
|
||||
task_runners_.GetUITaskRunner()->GetTaskQueueId());
|
||||
if (!success) {
|
||||
FML_LOG(ERROR)
|
||||
<< "Unable to move the UI task runner to the platform thread";
|
||||
}
|
||||
}
|
||||
|
||||
return Engine::RunStatus::Success;
|
||||
}
|
||||
|
||||
|
||||
@ -441,7 +441,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
/// @return The pointer to this instance of the engine. The engine may
|
||||
/// only be accessed safely on the UI task runner.
|
||||
///
|
||||
fml::WeakPtr<Engine> GetWeakPtr() const;
|
||||
fml::TaskRunnerAffineWeakPtr<Engine> GetWeakPtr() const;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Moves the root isolate to the `DartIsolate::Phase::Running`
|
||||
@ -877,7 +877,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
std::shared_ptr<AssetManager> GetAssetManager() override;
|
||||
|
||||
// Return the weak_ptr of ImageDecoder.
|
||||
fml::WeakPtr<ImageDecoder> GetImageDecoderWeakPtr();
|
||||
fml::TaskRunnerAffineWeakPtr<ImageDecoder> GetImageDecoderWeakPtr();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Get the `ImageGeneratorRegistry` associated with the current
|
||||
@ -885,7 +885,8 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
///
|
||||
/// @return The engine's `ImageGeneratorRegistry`.
|
||||
///
|
||||
fml::WeakPtr<ImageGeneratorRegistry> GetImageGeneratorRegistry();
|
||||
fml::TaskRunnerAffineWeakPtr<ImageGeneratorRegistry>
|
||||
GetImageGeneratorRegistry();
|
||||
|
||||
// |PointerDataDispatcher::Delegate|
|
||||
void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
|
||||
@ -1084,7 +1085,8 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate {
|
||||
const std::unique_ptr<ImageDecoder> image_decoder_;
|
||||
ImageGeneratorRegistry image_generator_registry_;
|
||||
TaskRunners task_runners_;
|
||||
fml::WeakPtrFactory<Engine> weak_factory_; // Must be the last member.
|
||||
fml::TaskRunnerAffineWeakPtrFactory<Engine>
|
||||
weak_factory_; // Must be the last member.
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(Engine);
|
||||
};
|
||||
|
||||
|
||||
@ -159,7 +159,8 @@ class SmoothPointerDataDispatcher : public DefaultPointerDataDispatcher {
|
||||
bool is_pointer_data_in_progress_ = false;
|
||||
|
||||
// WeakPtrFactory must be the last member.
|
||||
fml::WeakPtrFactory<SmoothPointerDataDispatcher> weak_factory_;
|
||||
fml::TaskRunnerAffineWeakPtrFactory<SmoothPointerDataDispatcher>
|
||||
weak_factory_;
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(SmoothPointerDataDispatcher);
|
||||
};
|
||||
|
||||
|
||||
@ -567,6 +567,19 @@ Shell::~Shell() {
|
||||
platform_latch.Signal();
|
||||
}));
|
||||
platform_latch.Wait();
|
||||
|
||||
if (settings_.merged_platform_ui_thread ==
|
||||
Settings::MergedPlatformUIThread::kMergeAfterLaunch) {
|
||||
// Move the UI task runner back to its original thread to enable shutdown of
|
||||
// that thread.
|
||||
auto task_queues = fml::MessageLoopTaskQueues::GetInstance();
|
||||
auto platform_queue_id =
|
||||
task_runners_.GetPlatformTaskRunner()->GetTaskQueueId();
|
||||
auto ui_queue_id = task_runners_.GetUITaskRunner()->GetTaskQueueId();
|
||||
if (task_queues->Owns(platform_queue_id, ui_queue_id)) {
|
||||
task_queues->Unmerge(platform_queue_id, ui_queue_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Shell> Shell::Spawn(
|
||||
@ -575,6 +588,16 @@ std::unique_ptr<Shell> Shell::Spawn(
|
||||
const CreateCallback<PlatformView>& on_create_platform_view,
|
||||
const CreateCallback<Rasterizer>& on_create_rasterizer) const {
|
||||
FML_DCHECK(task_runners_.IsValid());
|
||||
|
||||
if (settings_.merged_platform_ui_thread ==
|
||||
Settings::MergedPlatformUIThread::kMergeAfterLaunch) {
|
||||
// Spawning engines that share the same task runners can result in
|
||||
// deadlocks when the UI task runner is moved to the platform thread.
|
||||
FML_LOG(ERROR) << "MergedPlatformUIThread::kMergeAfterLaunch does not "
|
||||
"support spawning";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// It's safe to store this value since it is set on the platform thread.
|
||||
bool is_gpu_disabled = false;
|
||||
GetIsGpuDisabledSyncSwitch()->Execute(
|
||||
@ -811,7 +834,7 @@ fml::TaskRunnerAffineWeakPtr<Rasterizer> Shell::GetRasterizer() const {
|
||||
return weak_rasterizer_;
|
||||
}
|
||||
|
||||
fml::WeakPtr<Engine> Shell::GetEngine() {
|
||||
fml::TaskRunnerAffineWeakPtr<Engine> Shell::GetEngine() {
|
||||
FML_DCHECK(is_set_up_);
|
||||
return weak_engine_;
|
||||
}
|
||||
@ -1079,12 +1102,12 @@ void Shell::OnPlatformViewDispatchPlatformMessage(
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks)
|
||||
fml::TaskRunner::RunNowAndFlushMessages(
|
||||
task_runners_.GetUITaskRunner(),
|
||||
fml::MakeCopyable([engine = engine_->GetWeakPtr(),
|
||||
message = std::move(message)]() mutable {
|
||||
if (engine) {
|
||||
engine->DispatchPlatformMessage(std::move(message));
|
||||
}
|
||||
}));
|
||||
fml::MakeCopyable(
|
||||
[engine = weak_engine_, message = std::move(message)]() mutable {
|
||||
if (engine) {
|
||||
engine->DispatchPlatformMessage(std::move(message));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// |PlatformView::Delegate|
|
||||
|
||||
@ -260,7 +260,7 @@ class Shell final : public PlatformView::Delegate,
|
||||
///
|
||||
/// @return A weak pointer to the engine.
|
||||
///
|
||||
fml::WeakPtr<Engine> GetEngine();
|
||||
fml::TaskRunnerAffineWeakPtr<Engine> GetEngine();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Platform views may only be accessed on the platform task
|
||||
@ -470,7 +470,8 @@ class Shell final : public PlatformView::Delegate,
|
||||
std::shared_ptr<PlatformMessageHandler> platform_message_handler_;
|
||||
std::atomic<bool> route_messages_through_platform_thread_ = false;
|
||||
|
||||
fml::WeakPtr<Engine> weak_engine_; // to be shared across threads
|
||||
fml::TaskRunnerAffineWeakPtr<Engine>
|
||||
weak_engine_; // to be shared across threads
|
||||
fml::TaskRunnerAffineWeakPtr<Rasterizer>
|
||||
weak_rasterizer_; // to be shared across threads
|
||||
fml::WeakPtr<PlatformView>
|
||||
|
||||
@ -25,8 +25,10 @@ static void StartupAndShutdownShell(benchmark::State& state,
|
||||
{
|
||||
benchmarking::ScopedPauseTiming pause(state, !measure_startup);
|
||||
Settings settings = {};
|
||||
settings.task_observer_add = [](intptr_t, const fml::closure&) {};
|
||||
settings.task_observer_remove = [](intptr_t) {};
|
||||
settings.task_observer_add = [](intptr_t, const fml::closure&) {
|
||||
return fml::TaskQueueId::Invalid();
|
||||
};
|
||||
settings.task_observer_remove = [](fml::TaskQueueId, intptr_t) {};
|
||||
|
||||
if (DartVM::IsRunningPrecompiledCode()) {
|
||||
aot_symbols = testing::LoadELFSymbolFromFixturesIfNeccessary(
|
||||
|
||||
@ -226,7 +226,8 @@ void ShellTest::PumpOneFrame(Shell* shell, FrameContent frame_content) {
|
||||
// tree pipeline nonempty. Without either of this, the layer tree below
|
||||
// won't be rasterized.
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
fml::WeakPtr<RuntimeDelegate> runtime_delegate = shell->weak_engine_;
|
||||
fml::TaskRunnerAffineWeakPtr<RuntimeDelegate> runtime_delegate =
|
||||
shell->weak_engine_;
|
||||
shell->GetTaskRunners().GetUITaskRunner()->PostTask(
|
||||
[&latch, engine = shell->weak_engine_, &frame_content,
|
||||
runtime_delegate]() {
|
||||
@ -341,10 +342,14 @@ Settings ShellTest::CreateSettingsForFixture() {
|
||||
Settings settings;
|
||||
settings.leak_vm = false;
|
||||
settings.task_observer_add = [](intptr_t key, const fml::closure& handler) {
|
||||
fml::MessageLoop::GetCurrent().AddTaskObserver(key, handler);
|
||||
fml::TaskQueueId queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
|
||||
fml::MessageLoopTaskQueues::GetInstance()->AddTaskObserver(queue_id, key,
|
||||
handler);
|
||||
return queue_id;
|
||||
};
|
||||
settings.task_observer_remove = [](intptr_t key) {
|
||||
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
|
||||
settings.task_observer_remove = [](fml::TaskQueueId queue_id, intptr_t key) {
|
||||
fml::MessageLoopTaskQueues::GetInstance()->RemoveTaskObserver(queue_id,
|
||||
key);
|
||||
};
|
||||
settings.isolate_create_callback = [this]() {
|
||||
native_resolver_->SetNativeResolverForIsolate();
|
||||
|
||||
@ -5072,6 +5072,47 @@ TEST_F(ShellTest, ProvidesNullEngineId) {
|
||||
DestroyShell(std::move(shell), task_runners);
|
||||
}
|
||||
|
||||
TEST_F(ShellTest, MergeUIAndPlatformThreadsAfterLaunch) {
|
||||
Settings settings = CreateSettingsForFixture();
|
||||
settings.merged_platform_ui_thread =
|
||||
Settings::MergedPlatformUIThread::kMergeAfterLaunch;
|
||||
ThreadHost thread_host(ThreadHost::ThreadHostConfig(
|
||||
"io.flutter.test." + GetCurrentTestName() + ".",
|
||||
ThreadHost::Type::kPlatform | ThreadHost::Type::kRaster |
|
||||
ThreadHost::Type::kIo | ThreadHost::Type::kUi));
|
||||
TaskRunners task_runners("test", thread_host.platform_thread->GetTaskRunner(),
|
||||
thread_host.raster_thread->GetTaskRunner(),
|
||||
thread_host.ui_thread->GetTaskRunner(),
|
||||
thread_host.io_thread->GetTaskRunner());
|
||||
|
||||
std::unique_ptr<Shell> shell = CreateShell(settings, task_runners);
|
||||
ASSERT_TRUE(shell);
|
||||
|
||||
ASSERT_FALSE(fml::TaskRunnerChecker::RunsOnTheSameThread(
|
||||
task_runners.GetUITaskRunner()->GetTaskQueueId(),
|
||||
task_runners.GetPlatformTaskRunner()->GetTaskQueueId()));
|
||||
|
||||
fml::AutoResetWaitableEvent latch;
|
||||
AddNativeCallback(
|
||||
"NotifyNative", CREATE_NATIVE_ENTRY([&](auto args) {
|
||||
ASSERT_TRUE(
|
||||
task_runners.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
|
||||
latch.Signal();
|
||||
}));
|
||||
|
||||
auto configuration = RunConfiguration::InferFromSettings(settings);
|
||||
configuration.SetEntrypoint("mainNotifyNative");
|
||||
RunEngine(shell.get(), std::move(configuration));
|
||||
|
||||
latch.Wait();
|
||||
|
||||
ASSERT_TRUE(fml::TaskRunnerChecker::RunsOnTheSameThread(
|
||||
task_runners.GetUITaskRunner()->GetTaskQueueId(),
|
||||
task_runners.GetPlatformTaskRunner()->GetTaskQueueId()));
|
||||
|
||||
DestroyShell(std::move(shell), task_runners);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
|
||||
|
||||
@ -529,8 +529,26 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
|
||||
settings.enable_surface_control = command_line.HasOption(
|
||||
FlagForSwitch(Switch::EnableAndroidSurfaceControl));
|
||||
|
||||
settings.merged_platform_ui_thread = !command_line.HasOption(
|
||||
FlagForSwitch(Switch::DisableMergedPlatformUIThread));
|
||||
if (command_line.HasOption(
|
||||
FlagForSwitch(Switch::DisableMergedPlatformUIThread))) {
|
||||
settings.merged_platform_ui_thread =
|
||||
Settings::MergedPlatformUIThread::kDisabled;
|
||||
} else if (command_line.HasOption(
|
||||
FlagForSwitch(Switch::MergedPlatformUIThread))) {
|
||||
std::string merged_platform_ui;
|
||||
command_line.GetOptionValue(FlagForSwitch(Switch::MergedPlatformUIThread),
|
||||
&merged_platform_ui);
|
||||
if (merged_platform_ui == "enabled") {
|
||||
settings.merged_platform_ui_thread =
|
||||
Settings::MergedPlatformUIThread::kEnabled;
|
||||
} else if (merged_platform_ui == "disabled") {
|
||||
settings.merged_platform_ui_thread =
|
||||
Settings::MergedPlatformUIThread::kDisabled;
|
||||
} else if (merged_platform_ui == "mergeAfterLaunch") {
|
||||
settings.merged_platform_ui_thread =
|
||||
Settings::MergedPlatformUIThread::kMergeAfterLaunch;
|
||||
}
|
||||
}
|
||||
|
||||
settings.enable_flutter_gpu =
|
||||
command_line.HasOption(FlagForSwitch(Switch::EnableFlutterGPU));
|
||||
|
||||
@ -294,6 +294,11 @@ DEF_SWITCH(EnableEmbedderAPI,
|
||||
DEF_SWITCH(EnablePlatformIsolates,
|
||||
"enable-platform-isolates",
|
||||
"Enable support for isolates that run on the platform thread.")
|
||||
DEF_SWITCH(MergedPlatformUIThread,
|
||||
"merged-platform-ui-thread",
|
||||
"Sets whether the ui thread and platform thread should be merged.")
|
||||
// This is a legacy flag that has been superseded by merged-platform-ui-thread.
|
||||
// TODO(163064): remove this when users have been migrated.
|
||||
DEF_SWITCH(DisableMergedPlatformUIThread,
|
||||
"no-enable-merged-platform-ui-thread",
|
||||
"Merge the ui thread and platform thread.")
|
||||
|
||||
@ -90,7 +90,8 @@ AndroidShellHolder::AndroidShellHolder(
|
||||
auto thread_label = std::to_string(thread_host_count++);
|
||||
|
||||
auto mask = ThreadHost::Type::kRaster | ThreadHost::Type::kIo;
|
||||
if (!settings.merged_platform_ui_thread) {
|
||||
if (settings.merged_platform_ui_thread !=
|
||||
Settings::MergedPlatformUIThread::kEnabled) {
|
||||
mask |= ThreadHost::Type::kUi;
|
||||
}
|
||||
|
||||
@ -139,7 +140,8 @@ AndroidShellHolder::AndroidShellHolder(
|
||||
fml::RefPtr<fml::TaskRunner> platform_runner =
|
||||
fml::MessageLoop::GetCurrent().GetTaskRunner();
|
||||
raster_runner = thread_host_->raster_thread->GetTaskRunner();
|
||||
if (settings.merged_platform_ui_thread) {
|
||||
if (settings.merged_platform_ui_thread ==
|
||||
Settings::MergedPlatformUIThread::kEnabled) {
|
||||
ui_runner = platform_runner;
|
||||
} else {
|
||||
ui_runner = thread_host_->ui_thread->GetTaskRunner();
|
||||
|
||||
@ -201,7 +201,8 @@ TEST(AndroidShellHolder, CreateWithMergedPlatformAndUIThread) {
|
||||
|
||||
TEST(AndroidShellHolder, CreateWithUnMergedPlatformAndUIThread) {
|
||||
Settings settings;
|
||||
settings.merged_platform_ui_thread = false;
|
||||
settings.merged_platform_ui_thread =
|
||||
Settings::MergedPlatformUIThread::kDisabled;
|
||||
auto jni = std::make_shared<MockPlatformViewAndroidJNI>();
|
||||
auto holder = std::make_unique<AndroidShellHolder>(
|
||||
settings, jni, AndroidRenderingAPI::kImpellerOpenGLES);
|
||||
|
||||
@ -147,11 +147,15 @@ void FlutterMain::Init(JNIEnv* env,
|
||||
}
|
||||
|
||||
settings.task_observer_add = [](intptr_t key, const fml::closure& callback) {
|
||||
fml::MessageLoop::GetCurrent().AddTaskObserver(key, callback);
|
||||
fml::TaskQueueId queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
|
||||
fml::MessageLoopTaskQueues::GetInstance()->AddTaskObserver(queue_id, key,
|
||||
callback);
|
||||
return queue_id;
|
||||
};
|
||||
|
||||
settings.task_observer_remove = [](intptr_t key) {
|
||||
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
|
||||
settings.task_observer_remove = [](fml::TaskQueueId queue_id, intptr_t key) {
|
||||
fml::MessageLoopTaskQueues::GetInstance()->RemoveTaskObserver(queue_id,
|
||||
key);
|
||||
};
|
||||
|
||||
settings.log_message_callback = [](const std::string& tag,
|
||||
|
||||
@ -368,10 +368,8 @@ public class FlutterLoader {
|
||||
if (metaData.getBoolean(IMPELLER_VULKAN_GPU_TRACING_DATA_KEY, false)) {
|
||||
shellArgs.add("--enable-vulkan-gpu-tracing");
|
||||
}
|
||||
if (metaData.containsKey(DISABLE_MERGED_PLATFORM_UI_THREAD_KEY)) {
|
||||
if (metaData.getBoolean(DISABLE_MERGED_PLATFORM_UI_THREAD_KEY)) {
|
||||
shellArgs.add("--no-enable-merged-platform-ui-thread");
|
||||
}
|
||||
if (metaData.getBoolean(DISABLE_MERGED_PLATFORM_UI_THREAD_KEY, false)) {
|
||||
shellArgs.add("--merged-platform-ui-thread=disabled");
|
||||
}
|
||||
if (metaData.getBoolean(ENABLE_FLUTTER_GPU, false)) {
|
||||
shellArgs.add("--enable-flutter-gpu");
|
||||
|
||||
@ -64,11 +64,13 @@ flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle, NSProcessInfo* p
|
||||
auto settings = flutter::SettingsFromCommandLine(command_line);
|
||||
|
||||
settings.task_observer_add = [](intptr_t key, const fml::closure& callback) {
|
||||
fml::MessageLoop::GetCurrent().AddTaskObserver(key, callback);
|
||||
fml::TaskQueueId queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
|
||||
fml::MessageLoopTaskQueues::GetInstance()->AddTaskObserver(queue_id, key, callback);
|
||||
return queue_id;
|
||||
};
|
||||
|
||||
settings.task_observer_remove = [](intptr_t key) {
|
||||
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
|
||||
settings.task_observer_remove = [](fml::TaskQueueId queue_id, intptr_t key) {
|
||||
fml::MessageLoopTaskQueues::GetInstance()->RemoveTaskObserver(queue_id, key);
|
||||
};
|
||||
|
||||
settings.log_message_callback = [](const std::string& tag, const std::string& message) {
|
||||
@ -209,7 +211,9 @@ flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle, NSProcessInfo* p
|
||||
NSNumber* enableMergedPlatformUIThread =
|
||||
[mainBundle objectForInfoDictionaryKey:@"FLTEnableMergedPlatformUIThread"];
|
||||
if (enableMergedPlatformUIThread != nil) {
|
||||
settings.merged_platform_ui_thread = enableMergedPlatformUIThread.boolValue;
|
||||
settings.merged_platform_ui_thread = enableMergedPlatformUIThread.boolValue
|
||||
? flutter::Settings::MergedPlatformUIThread::kEnabled
|
||||
: flutter::Settings::MergedPlatformUIThread::kDisabled;
|
||||
}
|
||||
|
||||
NSNumber* enableFlutterGPU = [mainBundle objectForInfoDictionaryKey:@"FLTEnableFlutterGPU"];
|
||||
|
||||
@ -752,7 +752,7 @@ static flutter::ThreadHost MakeThreadHost(NSString* thread_label,
|
||||
fml::MessageLoop::EnsureInitializedForCurrentThread();
|
||||
|
||||
uint32_t threadHostType = flutter::ThreadHost::Type::kRaster | flutter::ThreadHost::Type::kIo;
|
||||
if (!settings.merged_platform_ui_thread) {
|
||||
if (settings.merged_platform_ui_thread != flutter::Settings::MergedPlatformUIThread::kEnabled) {
|
||||
threadHostType |= flutter::ThreadHost::Type::kUi;
|
||||
}
|
||||
|
||||
@ -839,7 +839,8 @@ static void SetEntryPoint(flutter::Settings* settings, NSString* entrypoint, NSS
|
||||
[](flutter::Shell& shell) { return std::make_unique<flutter::Rasterizer>(shell); };
|
||||
|
||||
fml::RefPtr<fml::TaskRunner> ui_runner;
|
||||
if (settings.enable_impeller && settings.merged_platform_ui_thread) {
|
||||
if (settings.enable_impeller &&
|
||||
settings.merged_platform_ui_thread == flutter::Settings::MergedPlatformUIThread::kEnabled) {
|
||||
ui_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();
|
||||
} else {
|
||||
ui_runner = _threadHost->ui_thread->GetTaskRunner();
|
||||
|
||||
@ -528,7 +528,7 @@ FLUTTER_ASSERT_ARC
|
||||
- (void)testCanUnMergePlatformAndUIThread {
|
||||
#if defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR
|
||||
auto settings = FLTDefaultSettingsForBundle();
|
||||
settings.merged_platform_ui_thread = false;
|
||||
settings.merged_platform_ui_thread = flutter::Settings::MergedPlatformUIThread::kDisabled;
|
||||
FlutterDartProject* project = [[FlutterDartProject alloc] initWithSettings:settings];
|
||||
FlutterEngine* engine = [[FlutterEngine alloc] initWithName:@"foobar" project:project];
|
||||
[engine run];
|
||||
|
||||
@ -2389,12 +2389,18 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
|
||||
settings.task_observer_add = [has_ui_thread_message_loop](
|
||||
intptr_t key, const fml::closure& callback) {
|
||||
if (has_ui_thread_message_loop) {
|
||||
fml::MessageLoop::GetCurrent().AddTaskObserver(key, callback);
|
||||
fml::TaskQueueId queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
|
||||
fml::MessageLoopTaskQueues::GetInstance()->AddTaskObserver(queue_id, key,
|
||||
callback);
|
||||
return queue_id;
|
||||
} else {
|
||||
return fml::TaskQueueId::Invalid();
|
||||
}
|
||||
};
|
||||
settings.task_observer_remove = [has_ui_thread_message_loop](intptr_t key) {
|
||||
if (has_ui_thread_message_loop) {
|
||||
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
|
||||
settings.task_observer_remove = [](fml::TaskQueueId queue_id, intptr_t key) {
|
||||
if (queue_id.is_valid()) {
|
||||
fml::MessageLoopTaskQueues::GetInstance()->RemoveTaskObserver(queue_id,
|
||||
key);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -469,8 +469,9 @@ ComponentV2::ComponentV2(
|
||||
std::bind(&fml::CurrentMessageLoopAddAfterTaskObserver,
|
||||
std::placeholders::_1, std::placeholders::_2);
|
||||
|
||||
settings_.task_observer_remove = std::bind(
|
||||
&fml::CurrentMessageLoopRemoveAfterTaskObserver, std::placeholders::_1);
|
||||
settings_.task_observer_remove =
|
||||
std::bind(&fml::CurrentMessageLoopRemoveAfterTaskObserver,
|
||||
std::placeholders::_1, std::placeholders::_2);
|
||||
|
||||
settings_.log_message_callback = [](const std::string& tag,
|
||||
const std::string& message) {
|
||||
|
||||
@ -666,11 +666,15 @@ int main(int argc, char* argv[]) {
|
||||
};
|
||||
|
||||
settings.task_observer_add = [](intptr_t key, const fml::closure& callback) {
|
||||
fml::MessageLoop::GetCurrent().AddTaskObserver(key, callback);
|
||||
fml::TaskQueueId queue_id = fml::MessageLoop::GetCurrentTaskQueueId();
|
||||
fml::MessageLoopTaskQueues::GetInstance()->AddTaskObserver(queue_id, key,
|
||||
callback);
|
||||
return queue_id;
|
||||
};
|
||||
|
||||
settings.task_observer_remove = [](intptr_t key) {
|
||||
fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
|
||||
settings.task_observer_remove = [](fml::TaskQueueId queue_id, intptr_t key) {
|
||||
fml::MessageLoopTaskQueues::GetInstance()->RemoveTaskObserver(queue_id,
|
||||
key);
|
||||
};
|
||||
|
||||
settings.unhandled_exception_callback = [](const std::string& error,
|
||||
|
||||
@ -30,8 +30,10 @@ DartFixture::DartFixture(std::string kernel_filename,
|
||||
Settings DartFixture::CreateSettingsForFixture() {
|
||||
Settings settings;
|
||||
settings.leak_vm = false;
|
||||
settings.task_observer_add = [](intptr_t, const fml::closure&) {};
|
||||
settings.task_observer_remove = [](intptr_t) {};
|
||||
settings.task_observer_add = [](intptr_t, const fml::closure&) {
|
||||
return fml::TaskQueueId::Invalid();
|
||||
};
|
||||
settings.task_observer_remove = [](fml::TaskQueueId, intptr_t) {};
|
||||
settings.isolate_create_callback = [this]() {
|
||||
native_resolver_->SetNativeResolverForIsolate();
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user