Chris Bracken 97eb094aac [flutter] Re-enable unhandled error reporting
This re-enables unhandled Dart error handling in Flutter applications,
which was removed in a76b958.

The error handling as originally landed was unsafe. Specifically, in the
case where the unhandled error handler was triggered during shutdown,
there was a race condition which could cause a crash in the following
scenario:
1. Runner::OnApplicationTerminate() is triggered, which posts a task to
   the application's platform thread will free the Application instance
   and terminate the platform thread.
2. Before that task is serviced, the unhandled error handler is called
   (by hooks.dart -> window.cc -> ui_dart_state.cc) on the UI thread.
3. The kill task is serviced and the Application dtor and Thread::Quit()
   are called, terminating the platform thread.
4. The unhandled error handler attempts to post a task to the platform
   thread, whose thread was killed in step 3. This triggers a crash.

Fixing this requires a mechanism for the message loop to know that the
associated thread has been terminated out from under it.

This patch adds mitigation for this scenario, but remains
non-threadsafe/racy. We pass the unhandled error handler a weak pointer
to the Application and check it before posting a task to the platform
thread. This has two issues:
1. WeakPtr isn't threadsafe, and assumes that all operations occur on a
   single thread. We're checking its value (which is mutated on the
   platform thread) on the UI thread without synchronization.
2. Even with a guarantee that the WeakPtr state were synchronized,
   there's a window between when we check the weak pointer and when we
   post to the platform thread in which application shutdown and thread
   destruction may occur.

This unsafe mitigation is being landed in order to unblock a high
priority bug (FL-256) on a short schedule, and a proper refactoring will
be required to make this properly threadsafe.

Change-Id: If60d1d3ca5799d82597f8a3acc4ddd3871058972

Ported from Topaz tree.
2019-06-28 17:40:00 -07:00

115 lines
4.0 KiB
C++

// Copyright 2013 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_SHELL_PLATFORM_FUCHSIA_COMPONENT_H_
#define FLUTTER_SHELL_PLATFORM_FUCHSIA_COMPONENT_H_
#include <array>
#include <memory>
#include <set>
#include <fuchsia/io/cpp/fidl.h>
#include <fuchsia/sys/cpp/fidl.h>
#include <fuchsia/ui/app/cpp/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/default.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/fit/function.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/vfs/cpp/pseudo_dir.h>
#include <lib/zx/eventpair.h>
#include "engine.h"
#include "flutter/common/settings.h"
#include "flutter/fml/macros.h"
#include "thread.h"
#include "unique_fdio_ns.h"
namespace flutter_runner {
// Represents an instance of a Flutter application that contains one of more
// Flutter engine instances.
class Application final : public Engine::Delegate,
public fuchsia::sys::ComponentController,
public fuchsia::ui::app::ViewProvider {
public:
using TerminationCallback = fit::function<void(const Application*)>;
// Creates a dedicated thread to run the application and constructions the
// application on it. The application can be accessed only on this thread.
// This is a synchronous operation.
static std::pair<std::unique_ptr<Thread>, std::unique_ptr<Application>>
Create(TerminationCallback termination_callback,
fuchsia::sys::Package package,
fuchsia::sys::StartupInfo startup_info,
std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller);
// Must be called on the same thread returned from the create call. The thread
// may be collected after.
~Application();
const std::string& GetDebugLabel() const;
#if !defined(DART_PRODUCT)
void WriteProfileToTrace() const;
#endif // !defined(DART_PRODUCT)
private:
flutter::Settings settings_;
TerminationCallback termination_callback_;
const std::string debug_label_;
UniqueFDIONS fdio_ns_ = UniqueFDIONSCreate();
fml::UniqueFD application_directory_;
fml::UniqueFD application_assets_directory_;
fidl::Binding<fuchsia::sys::ComponentController> application_controller_;
fuchsia::io::DirectoryPtr directory_ptr_;
fuchsia::io::NodePtr cloned_directory_ptr_;
fidl::InterfaceRequest<fuchsia::io::Directory> directory_request_;
std::unique_ptr<vfs::PseudoDir> outgoing_dir_;
std::shared_ptr<sys::ServiceDirectory> svc_;
std::shared_ptr<sys::ServiceDirectory> runner_incoming_services_;
fidl::BindingSet<fuchsia::ui::app::ViewProvider> shells_bindings_;
fml::RefPtr<flutter::DartSnapshot> isolate_snapshot_;
fml::RefPtr<flutter::DartSnapshot> shared_snapshot_;
std::set<std::unique_ptr<Engine>> shell_holders_;
std::pair<bool, uint32_t> last_return_code_;
fml::WeakPtrFactory<Application> weak_factory_;
Application(
TerminationCallback termination_callback,
fuchsia::sys::Package package,
fuchsia::sys::StartupInfo startup_info,
std::shared_ptr<sys::ServiceDirectory> runner_incoming_services,
fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller);
// |fuchsia::sys::ComponentController|
void Kill() override;
// |fuchsia::sys::ComponentController|
void Detach() override;
// |fuchsia::ui::app::ViewProvider|
void CreateView(
zx::eventpair view_token,
fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> incoming_services,
fidl::InterfaceHandle<fuchsia::sys::ServiceProvider> outgoing_services)
override;
// |flutter::Engine::Delegate|
void OnEngineTerminate(const Engine* holder) override;
void AttemptVMLaunchWithCurrentSettings(const flutter::Settings& settings);
FML_DISALLOW_COPY_AND_ASSIGN(Application);
};
} // namespace flutter_runner
#endif // FLUTTER_SHELL_PLATFORM_FUCHSIA_COMPONENT_H_