diff --git a/BUILD.gn b/BUILD.gn index b37b0b8d4054c..24dda026c6245 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -10,12 +10,14 @@ group("flutter") { public_deps = [ "$flutter_root/lib/snapshot:generate_snapshot_bin", "$flutter_root/lib/snapshot:kernel_platform_files", - "$flutter_root/shell/testing", "$flutter_root/sky", + "$flutter_root/third_party/txt", ] if (flutter_runtime_mode != "debug") { - public_deps += [ "$flutter_root/lib/snapshot:entry_points_json_files" ] + public_deps += [ + "$flutter_root/lib/snapshot:entry_points_json_files", + ] } if (!is_fuchsia && !is_fuchsia_host) { @@ -43,24 +45,20 @@ group("flutter") { "$flutter_root/shell/platform/embedder:flutter_embedder_framework", ] } - + if (!is_win) { + public_deps += [ + "$flutter_root/shell/platform/embedder:embedder_unittests", + "$flutter_root/shell/platform/embedder:flutter_engine", + ] + } public_deps += [ "$flutter_root/flow:flow_unittests", "$flutter_root/fml:fml_unittests", - "$flutter_root/runtime:runtime_unittests", - "$flutter_root/shell/common:shell_unittests", "$flutter_root/sky/engine/wtf:wtf_unittests", "$flutter_root/synchronization:synchronization_unittests", "$flutter_root/third_party/txt:txt_unittests", "//garnet/public/lib/fxl:fxl_unittests", ] - - if (!is_win) { - public_deps += [ - "$flutter_root/shell/platform/embedder:embedder_unittests", - "$flutter_root/shell/platform/embedder:flutter_engine", - ] - } } } @@ -76,23 +74,29 @@ if (is_fuchsia) { "$flutter_root/content_handler:aot", ] if (flutter_runtime_mode != "release") { - deps += [ "//third_party/dart/runtime/observatory:embedded_archive_observatory" ] + deps += [ + "//third_party/dart/runtime/observatory:embedded_archive_observatory", + ] } binary = "flutter_aot_runner" if (flutter_runtime_mode != "release") { - resources = [ { - path = rebase_path( - "$root_gen_dir/observatory/embedded_archive_observatory.tar") - dest = "observatory.tar" - } ] + resources = [ + { + path = rebase_path( + "$root_gen_dir/observatory/embedded_archive_observatory.tar") + dest = "observatory.tar" + }, + ] } - meta = [ { - path = rebase_path("content_handler/meta/sandbox") - dest = "sandbox" - } ] + meta = [ + { + path = rebase_path("content_handler/meta/sandbox") + dest = "sandbox" + }, + ] } package("flutter_jit_runner") { @@ -100,23 +104,29 @@ if (is_fuchsia) { "$flutter_root/content_handler:jit", ] if (flutter_runtime_mode != "release") { - deps += [ "//third_party/dart/runtime/observatory:embedded_archive_observatory" ] + deps += [ + "//third_party/dart/runtime/observatory:embedded_archive_observatory", + ] } binary = "flutter_jit_runner" if (flutter_runtime_mode != "release") { - resources = [ { - path = rebase_path( - "$root_gen_dir/observatory/embedded_archive_observatory.tar") - dest = "observatory.tar" - } ] + resources = [ + { + path = rebase_path( + "$root_gen_dir/observatory/embedded_archive_observatory.tar") + dest = "observatory.tar" + }, + ] } - meta = [ { - path = rebase_path("content_handler/meta/sandbox") - dest = "sandbox" - } ] + meta = [ + { + path = rebase_path("content_handler/meta/sandbox") + dest = "sandbox" + }, + ] } } else { group("dist") { diff --git a/DEPS b/DEPS index 0f47bd8ceeecb..30a88e2b6a355 100644 --- a/DEPS +++ b/DEPS @@ -115,7 +115,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + '3cf97e01cdbd4bb920fa3d40282a56c4b2d62a58', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '8dddd90bf943a8174913564353b30a3b11ee0f7a', # Fuchsia compatibility # diff --git a/assets/BUILD.gn b/assets/BUILD.gn index 28d7e569659f1..c4901375ad810 100644 --- a/assets/BUILD.gn +++ b/assets/BUILD.gn @@ -4,18 +4,16 @@ source_set("assets") { sources = [ - "asset_manager.cc", - "asset_manager.h", - "asset_resolver.h", + "asset_provider.h", "directory_asset_bundle.cc", "directory_asset_bundle.h", + "unzipper_provider.cc", + "unzipper_provider.h", "zip_asset_store.cc", "zip_asset_store.h", ] deps = [ - "$flutter_root/common", - "$flutter_root/fml", "$flutter_root/glue", "//garnet/public/lib/fxl", "//garnet/public/lib/zip", @@ -25,5 +23,7 @@ source_set("assets") { "//third_party/zlib:minizip", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] } diff --git a/assets/asset_manager.cc b/assets/asset_manager.cc deleted file mode 100644 index 8a313f0729c96..0000000000000 --- a/assets/asset_manager.cc +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/assets/asset_manager.h" - -#include "flutter/assets/directory_asset_bundle.h" -#include "flutter/assets/zip_asset_store.h" -#include "flutter/glue/trace_event.h" -#include "lib/fxl/files/path.h" - -namespace blink { - -AssetManager::AssetManager() = default; - -AssetManager::~AssetManager() = default; - -void AssetManager::PushFront(std::unique_ptr resolver) { - if (resolver == nullptr || !resolver->IsValid()) { - return; - } - - resolvers_.push_front(std::move(resolver)); -} - -void AssetManager::PushBack(std::unique_ptr resolver) { - if (resolver == nullptr || !resolver->IsValid()) { - return; - } - - resolvers_.push_back(std::move(resolver)); -} - -// |blink::AssetResolver| -bool AssetManager::GetAsBuffer(const std::string& asset_name, - std::vector* data) const { - if (asset_name.size() == 0) { - return false; - } - TRACE_EVENT0("flutter", "AssetManager::GetAsBuffer"); - for (const auto& resolver : resolvers_) { - if (resolver->GetAsBuffer(asset_name, data)) { - return true; - } - } - FXL_DLOG(ERROR) << "Could not find asset: " << asset_name; - return false; -} - -// |blink::AssetResolver| -bool AssetManager::IsValid() const { - return resolvers_.size() > 0; -} - -} // namespace blink diff --git a/assets/asset_manager.h b/assets/asset_manager.h deleted file mode 100644 index fc7f3ef05210e..0000000000000 --- a/assets/asset_manager.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017 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_ASSETS_ASSET_MANAGER_H_ -#define FLUTTER_ASSETS_ASSET_MANAGER_H_ - -#include -#include -#include - -#include "flutter/assets/asset_resolver.h" -#include "lib/fxl/files/unique_fd.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/ref_counted.h" - -namespace blink { - -class AssetManager final : public AssetResolver, - public fxl::RefCountedThreadSafe { - public: - void PushFront(std::unique_ptr resolver); - - void PushBack(std::unique_ptr resolver); - - // |blink::AssetResolver| - bool IsValid() const override; - - // |blink::AssetResolver| - bool GetAsBuffer(const std::string& asset_name, - std::vector* data) const override; - - private: - std::deque> resolvers_; - - AssetManager(); - - ~AssetManager(); - - FXL_DISALLOW_COPY_AND_ASSIGN(AssetManager); - FRIEND_MAKE_REF_COUNTED(AssetManager); - FRIEND_REF_COUNTED_THREAD_SAFE(AssetManager); -}; - -} // namespace blink - -#endif // FLUTTER_ASSETS_ASSET_MANAGER_H_ diff --git a/assets/asset_provider.h b/assets/asset_provider.h new file mode 100644 index 0000000000000..68b7f5c2b7b9c --- /dev/null +++ b/assets/asset_provider.h @@ -0,0 +1,25 @@ +// Copyright 2018 The Chromium 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_ASSETS_ASSET_PROVIDER_H_ +#define FLUTTER_ASSETS_ASSET_PROVIDER_H_ + +#include +#include + +#include "lib/fxl/memory/ref_counted.h" + +namespace blink { + +class AssetProvider + : public fxl::RefCountedThreadSafe + { + public: + virtual bool GetAsBuffer(const std::string& asset_name, + std::vector* data) = 0; + virtual ~AssetProvider() = default; +}; + +} // namespace blink +#endif // FLUTTER_ASSETS_ASSET_PROVIDER_H diff --git a/assets/asset_resolver.h b/assets/asset_resolver.h deleted file mode 100644 index 6cfe27961a9f4..0000000000000 --- a/assets/asset_resolver.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2017 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_ASSETS_ASSET_RESOLVER_H_ -#define FLUTTER_ASSETS_ASSET_RESOLVER_H_ - -#include -#include - -#include "lib/fxl/macros.h" - -namespace blink { - -class AssetResolver { - public: - AssetResolver() = default; - - virtual ~AssetResolver() = default; - - virtual bool IsValid() const = 0; - - virtual bool GetAsBuffer(const std::string& asset_name, - std::vector* data) const = 0; - - private: - FXL_DISALLOW_COPY_AND_ASSIGN(AssetResolver); -}; - -} // namespace blink - -#endif // FLUTTER_ASSETS_ASSET_RESOLVER_H_ diff --git a/assets/directory_asset_bundle.cc b/assets/directory_asset_bundle.cc index 8e5d4df2ab977..43933079a81bd 100644 --- a/assets/directory_asset_bundle.cc +++ b/assets/directory_asset_bundle.cc @@ -3,54 +3,73 @@ // found in the LICENSE file. #include "flutter/assets/directory_asset_bundle.h" +#include "lib/fxl/build_config.h" + +#include #include -#include "flutter/fml/file.h" -#include "flutter/fml/mapping.h" #include "lib/fxl/files/eintr_wrapper.h" +#include "lib/fxl/files/file.h" +#include "lib/fxl/files/path.h" +#include "lib/fxl/files/unique_fd.h" +#include "lib/fxl/portable_unistd.h" namespace blink { -DirectoryAssetBundle::DirectoryAssetBundle(fml::UniqueFD descriptor) - : descriptor_(std::move(descriptor)) { - if (!fml::IsDirectory(descriptor_)) { - return; - } - is_valid_ = true; -} +bool DirectoryAssetBundle::GetAsBuffer(const std::string& asset_name, + std::vector* data) { + if (fd_.is_valid()) { +#if defined(OS_WIN) + // This code path is not valid in a Windows environment. + return false; +#else + fxl::UniqueFD asset_file(openat(fd_.get(), asset_name.c_str(), O_RDONLY)); + if (!asset_file.is_valid()) + return false; -DirectoryAssetBundle::~DirectoryAssetBundle() = default; + constexpr size_t kBufferSize = 1 << 16; + size_t offset = 0; + ssize_t bytes_read = 0; + do { + offset += bytes_read; + data->resize(offset + kBufferSize); + bytes_read = read(asset_file.get(), &(*data)[offset], kBufferSize); + } while (bytes_read > 0); -// |blink::AssetResolver| -bool DirectoryAssetBundle::IsValid() const { - return is_valid_; -} + if (bytes_read < 0) { + FXL_LOG(ERROR) << "Reading " << asset_name << " failed"; + data->clear(); + return false; + } -// |blink::AssetResolver| -bool DirectoryAssetBundle::GetAsBuffer(const std::string& asset_name, - std::vector* data) const { - if (data == nullptr) { - return false; + data->resize(offset + bytes_read); + return true; +#endif } - - if (!is_valid_) { - FXL_DLOG(WARNING) << "Asset bundle was not valid."; + std::string asset_path = GetPathForAsset(asset_name); + if (asset_path.empty()) return false; - } + return files::ReadFileToVector(asset_path, data); +} - fml::FileMapping mapping( - fml::OpenFile(descriptor_, asset_name.c_str(), fml::OpenPermission::kRead, - false /* directory */), - false /* executable */); +DirectoryAssetBundle::~DirectoryAssetBundle() {} - if (mapping.GetMapping() == nullptr) { - return false; - } +DirectoryAssetBundle::DirectoryAssetBundle(std::string directory) + : directory_(std::move(directory)), fd_() {} + +DirectoryAssetBundle::DirectoryAssetBundle(fxl::UniqueFD fd) + : fd_(std::move(fd)) {} - data->resize(mapping.GetSize()); - memmove(data->data(), mapping.GetMapping(), mapping.GetSize()); - return true; +std::string DirectoryAssetBundle::GetPathForAsset( + const std::string& asset_name) { + std::string asset_path = files::SimplifyPath(directory_ + "/" + asset_name); + if (asset_path.find(directory_) != 0u) { + FXL_LOG(ERROR) << "Asset name '" << asset_name + << "' attempted to traverse outside asset bundle."; + return std::string(); + } + return asset_path; } } // namespace blink diff --git a/assets/directory_asset_bundle.h b/assets/directory_asset_bundle.h index b594e1357fbe2..c710a513796ae 100644 --- a/assets/directory_asset_bundle.h +++ b/assets/directory_asset_bundle.h @@ -5,31 +5,31 @@ #ifndef FLUTTER_ASSETS_DIRECTORY_ASSET_BUNDLE_H_ #define FLUTTER_ASSETS_DIRECTORY_ASSET_BUNDLE_H_ -#include "flutter/assets/asset_resolver.h" -#include "flutter/fml/unique_fd.h" +#include +#include + +#include "flutter/assets/asset_provider.h" +#include "lib/fxl/files/unique_fd.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_counted.h" namespace blink { -class DirectoryAssetBundle : public AssetResolver { +class DirectoryAssetBundle + : public AssetProvider { public: - explicit DirectoryAssetBundle(fml::UniqueFD descriptor); - - ~DirectoryAssetBundle() override; + explicit DirectoryAssetBundle(std::string directory); + // Expects fd to be valid, otherwise the file descriptor is ignored. + explicit DirectoryAssetBundle(fxl::UniqueFD fd); + virtual ~DirectoryAssetBundle(); - private: - const fml::UniqueFD descriptor_; - bool is_valid_ = false; + virtual bool GetAsBuffer(const std::string& asset_name, std::vector* data); - std::string GetPathForAsset(const std::string& asset_name) const; + std::string GetPathForAsset(const std::string& asset_name); - // |blink::AssetResolver| - bool IsValid() const override; - - // |blink::AssetResolver| - bool GetAsBuffer(const std::string& asset_name, - std::vector* data) const override; + private: + const std::string directory_; + fxl::UniqueFD fd_; FXL_DISALLOW_COPY_AND_ASSIGN(DirectoryAssetBundle); }; diff --git a/assets/unzipper_provider.cc b/assets/unzipper_provider.cc new file mode 100644 index 0000000000000..8ed023f9a20e9 --- /dev/null +++ b/assets/unzipper_provider.cc @@ -0,0 +1,21 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/assets/unzipper_provider.h" + +#include "lib/fxl/logging.h" +#include "third_party/zlib/contrib/minizip/unzip.h" + +namespace blink { + +UnzipperProvider GetUnzipperProviderForPath(std::string zip_path) { + return [zip_path]() { + zip::UniqueUnzipper unzipper(unzOpen2(zip_path.c_str(), nullptr)); + if (!unzipper.is_valid()) + FXL_LOG(ERROR) << "Unable to open zip file: " << zip_path; + return unzipper; + }; +} + +} // namespace blink diff --git a/assets/unzipper_provider.h b/assets/unzipper_provider.h new file mode 100644 index 0000000000000..f0f8d9597dffd --- /dev/null +++ b/assets/unzipper_provider.h @@ -0,0 +1,20 @@ +// Copyright 2016 The Chromium 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_ASSETS_UNZIP_PROVIDER_H_ +#define FLUTTER_ASSETS_UNZIP_PROVIDER_H_ + +#include + +#include "lib/zip/unique_unzipper.h" + +namespace blink { + +using UnzipperProvider = std::function; + +UnzipperProvider GetUnzipperProviderForPath(std::string zip_path); + +} // namespace blink + +#endif // FLUTTER_ASSETS_UNZIP_PROVIDER_H_ diff --git a/assets/zip_asset_store.cc b/assets/zip_asset_store.cc index 1b9216bd34530..c8534fa10c216 100644 --- a/assets/zip_asset_store.cc +++ b/assets/zip_asset_store.cc @@ -15,28 +15,21 @@ #include #include "flutter/glue/trace_event.h" +#include "lib/fxl/files/eintr_wrapper.h" +#include "lib/fxl/files/unique_fd.h" +#include "lib/zip/unique_unzipper.h" namespace blink { -ZipAssetStore::ZipAssetStore(std::string file_path) - : file_path_(std::move(file_path)) { +ZipAssetStore::ZipAssetStore(UnzipperProvider unzipper_provider) + : unzipper_provider_(std::move(unzipper_provider)) { BuildStatCache(); } ZipAssetStore::~ZipAssetStore() = default; -zip::UniqueUnzipper ZipAssetStore::CreateUnzipper() const { - return zip::UniqueUnzipper{::unzOpen2(file_path_.c_str(), nullptr)}; -} - -// |blink::AssetResolver| -bool ZipAssetStore::IsValid() const { - return stat_cache_.size() > 0; -} - -// |blink::AssetResolver| bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, - std::vector* data) const { + std::vector* data) { TRACE_EVENT0("flutter", "ZipAssetStore::GetAsBuffer"); auto found = stat_cache_.find(asset_name); @@ -44,7 +37,7 @@ bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, return false; } - auto unzipper = CreateUnzipper(); + auto unzipper = unzipper_provider_(); if (!unzipper.is_valid()) { return false; @@ -80,8 +73,7 @@ bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, void ZipAssetStore::BuildStatCache() { TRACE_EVENT0("flutter", "ZipAssetStore::BuildStatCache"); - - auto unzipper = CreateUnzipper(); + auto unzipper = unzipper_provider_(); if (!unzipper.is_valid()) { return; diff --git a/assets/zip_asset_store.h b/assets/zip_asset_store.h index 558678e25bc08..1ffda483ba9b7 100644 --- a/assets/zip_asset_store.h +++ b/assets/zip_asset_store.h @@ -6,20 +6,21 @@ #define FLUTTER_ASSETS_ZIP_ASSET_STORE_H_ #include +#include -#include "flutter/assets/asset_resolver.h" +#include "flutter/assets/unzipper_provider.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_counted.h" -#include "lib/zip/unique_unzipper.h" #include "third_party/zlib/contrib/minizip/unzip.h" namespace blink { -class ZipAssetStore final : public AssetResolver { +class ZipAssetStore : public fxl::RefCountedThreadSafe { public: - ZipAssetStore(std::string file_path); + explicit ZipAssetStore(UnzipperProvider unzipper_provider); + ~ZipAssetStore(); - ~ZipAssetStore() override; + bool GetAsBuffer(const std::string& asset_name, std::vector* data); private: struct CacheEntry { @@ -29,20 +30,11 @@ class ZipAssetStore final : public AssetResolver { : file_pos(p_file_pos), uncompressed_size(p_uncompressed_size) {} }; - std::string file_path_; - mutable std::map stat_cache_; - - // |blink::AssetResolver| - bool IsValid() const override; - - // |blink::AssetResolver| - bool GetAsBuffer(const std::string& asset_name, - std::vector* data) const override; + UnzipperProvider unzipper_provider_; + std::map stat_cache_; void BuildStatCache(); - zip::UniqueUnzipper CreateUnzipper() const; - FXL_DISALLOW_COPY_AND_ASSIGN(ZipAssetStore); }; diff --git a/common/BUILD.gn b/common/BUILD.gn index 47cd7d3d62644..53b71914d49d1 100644 --- a/common/BUILD.gn +++ b/common/BUILD.gn @@ -12,12 +12,11 @@ source_set("common") { sources = [ "settings.cc", "settings.h", - "task_runners.cc", - "task_runners.h", + "threads.cc", + "threads.h", ] deps = [ - "$flutter_root/fml", "//garnet/public/lib/fxl", ] diff --git a/common/settings.cc b/common/settings.cc index 85523e1b9a29f..0198f714cbaad 100644 --- a/common/settings.cc +++ b/common/settings.cc @@ -4,50 +4,26 @@ #include "flutter/common/settings.h" -#include +#include + +#include "lib/fxl/logging.h" namespace blink { +namespace { + +Settings* g_settings = nullptr; + +} // namespace + +const Settings& Settings::Get() { + FXL_CHECK(g_settings); + return *g_settings; +} -std::string Settings::ToString() const { - std::stringstream stream; - stream << "Settings: " << std::endl; - stream << "aot_snapshot_path: " << aot_snapshot_path << std::endl; - stream << "script_snapshot_path: " << script_snapshot_path << std::endl; - stream << "aot_vm_snapshot_data_filename: " << aot_vm_snapshot_data_filename - << std::endl; - stream << "aot_vm_snapshot_instr_filename: " << aot_vm_snapshot_instr_filename - << std::endl; - stream << "aot_isolate_snapshot_data_filename: " - << aot_isolate_snapshot_data_filename << std::endl; - stream << "aot_isolate_snapshot_instr_filename: " - << aot_isolate_snapshot_instr_filename << std::endl; - stream << "application_library_path: " << application_library_path - << std::endl; - stream << "main_dart_file_path: " << main_dart_file_path << std::endl; - stream << "packages_file_path: " << packages_file_path << std::endl; - stream << "temp_directory_path: " << temp_directory_path << std::endl; - stream << "dart_flags:" << std::endl; - for (const auto& dart_flag : dart_flags) { - stream << " " << dart_flag << std::endl; - } - stream << "start_paused: " << start_paused << std::endl; - stream << "trace_skia: " << trace_skia << std::endl; - stream << "trace_startup: " << trace_startup << std::endl; - stream << "endless_trace_buffer: " << endless_trace_buffer << std::endl; - stream << "enable_dart_profiling: " << enable_dart_profiling << std::endl; - stream << "dart_non_checked_mode: " << dart_non_checked_mode << std::endl; - stream << "enable_observatory: " << enable_observatory << std::endl; - stream << "observatory_port: " << observatory_port << std::endl; - stream << "ipv6: " << ipv6 << std::endl; - stream << "use_test_fonts: " << use_test_fonts << std::endl; - stream << "enable_software_rendering: " << enable_software_rendering - << std::endl; - stream << "using_blink: " << using_blink << std::endl; - stream << "log_tag: " << log_tag << std::endl; - stream << "icu_data_path: " << icu_data_path << std::endl; - stream << "assets_dir: " << assets_dir << std::endl; - stream << "assets_path: " << assets_path << std::endl; - return stream.str(); +void Settings::Set(const Settings& settings) { + FXL_CHECK(!g_settings); + g_settings = new Settings(); + *g_settings = settings; } } // namespace blink diff --git a/common/settings.h b/common/settings.h index c6c3159766a37..5bb5c6cbbea42 100644 --- a/common/settings.h +++ b/common/settings.h @@ -5,82 +5,40 @@ #ifndef FLUTTER_COMMON_SETTINGS_H_ #define FLUTTER_COMMON_SETTINGS_H_ -#include #include -#include #include #include -#include "flutter/fml/unique_fd.h" -#include "lib/fxl/functional/closure.h" - namespace blink { -using TaskObserverAdd = - std::function; -using TaskObserverRemove = std::function; - struct Settings { - // VM settings - std::string script_snapshot_path; - std::string kernel_snapshot_path; - + bool enable_observatory = false; + // Port on target will be auto selected by the OS. A message will be printed + // on the target with the port after it has been selected. + uint32_t observatory_port = 0; + bool ipv6 = false; + bool start_paused = false; + bool trace_startup = false; + bool endless_trace_buffer = false; + bool enable_dart_profiling = false; + bool use_test_fonts = false; + bool dart_non_checked_mode = false; + bool enable_software_rendering = false; + bool using_blink = true; + std::string aot_shared_library_path; std::string aot_snapshot_path; std::string aot_vm_snapshot_data_filename; std::string aot_vm_snapshot_instr_filename; std::string aot_isolate_snapshot_data_filename; std::string aot_isolate_snapshot_instr_filename; - std::string application_library_path; - std::string application_kernel_asset; - - std::string main_dart_file_path; - std::string packages_file_path; - std::string temp_directory_path; std::vector dart_flags; - - // Isolate settings - bool start_paused = false; - bool trace_skia = false; - bool trace_startup = false; - bool endless_trace_buffer = false; - bool enable_dart_profiling = false; - bool dart_non_checked_mode = false; - - // Observatory settings - bool enable_observatory = false; - // Port on target will be auto selected by the OS. A message will be printed - // on the target with the port after it has been selected. - uint32_t observatory_port = 0; - bool ipv6 = false; - - // Font settings - bool use_test_fonts = false; - - // Engine settings - TaskObserverAdd task_observer_add; - TaskObserverRemove task_observer_remove; - // The main isolate is current when this callback is made. This is a good spot - // to perform native Dart bindings for libraries not built in. - fxl::Closure root_isolate_create_callback; - // The isolate is not current and may have already been destroyed when this - // call is made. - fxl::Closure root_isolate_shutdown_callback; - bool enable_software_rendering = false; - bool using_blink = false; - bool skia_deterministic_rendering_on_cpu = false; std::string log_tag = "flutter"; - std::string icu_data_path; - - // Assets settings - fml::UniqueFD::element_type assets_dir = - fml::UniqueFD::traits_type::InvalidValue(); - std::string assets_path; - std::string flx_path; - std::string ToString() const; + static const Settings& Get(); + static void Set(const Settings& settings); }; } // namespace blink diff --git a/common/task_runners.cc b/common/task_runners.cc deleted file mode 100644 index 1a09daec1815c..0000000000000 --- a/common/task_runners.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/common/task_runners.h" - -#include - -namespace blink { - -TaskRunners::TaskRunners(std::string label, - fxl::RefPtr platform, - fxl::RefPtr gpu, - fxl::RefPtr ui, - fxl::RefPtr io) - : label_(std::move(label)), - platform_(std::move(platform)), - gpu_(std::move(gpu)), - ui_(std::move(ui)), - io_(std::move(io)) {} - -TaskRunners::~TaskRunners() = default; - -const std::string& TaskRunners::GetLabel() const { - return label_; -} - -fxl::RefPtr TaskRunners::GetPlatformTaskRunner() const { - return platform_; -} - -fxl::RefPtr TaskRunners::GetUITaskRunner() const { - return ui_; -} - -fxl::RefPtr TaskRunners::GetIOTaskRunner() const { - return io_; -} - -fxl::RefPtr TaskRunners::GetGPUTaskRunner() const { - return gpu_; -} - -bool TaskRunners::IsValid() const { - return platform_ && gpu_ && ui_ && io_; -} - -} // namespace blink diff --git a/common/task_runners.h b/common/task_runners.h deleted file mode 100644 index f41ae147ebad0..0000000000000 --- a/common/task_runners.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2017 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_COMMON_TASK_RUNNERS_H_ -#define FLUTTER_COMMON_TASK_RUNNERS_H_ - -#include - -#include "lib/fxl/macros.h" -#include "lib/fxl/tasks/task_runner.h" - -namespace blink { - -class TaskRunners { - public: - TaskRunners(std::string label, - fxl::RefPtr platform, - fxl::RefPtr gpu, - fxl::RefPtr ui, - fxl::RefPtr io); - - ~TaskRunners(); - - const std::string& GetLabel() const; - - fxl::RefPtr GetPlatformTaskRunner() const; - - fxl::RefPtr GetUITaskRunner() const; - - fxl::RefPtr GetIOTaskRunner() const; - - fxl::RefPtr GetGPUTaskRunner() const; - - bool IsValid() const; - - private: - const std::string label_; - fxl::RefPtr platform_; - fxl::RefPtr gpu_; - fxl::RefPtr ui_; - fxl::RefPtr io_; -}; -} // namespace blink - -#endif // FLUTTER_COMMON_TASK_RUNNERS_H_ diff --git a/common/threads.cc b/common/threads.cc new file mode 100644 index 0000000000000..3634d8d7c8723 --- /dev/null +++ b/common/threads.cc @@ -0,0 +1,56 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/common/threads.h" + +#include + +namespace blink { +namespace { + +Threads* g_threads = nullptr; + +} // namespace + +Threads::Threads() {} + +Threads::Threads(fxl::RefPtr platform, + fxl::RefPtr gpu, + fxl::RefPtr ui, + fxl::RefPtr io) + : platform_(std::move(platform)), + gpu_(std::move(gpu)), + ui_(std::move(ui)), + io_(std::move(io)) {} + +Threads::~Threads() {} + +const fxl::RefPtr& Threads::Platform() { + return Get().platform_; +} + +const fxl::RefPtr& Threads::Gpu() { + return Get().gpu_; +} + +const fxl::RefPtr& Threads::UI() { + return Get().ui_; +} + +const fxl::RefPtr& Threads::IO() { + return Get().io_; +} + +const Threads& Threads::Get() { + FXL_CHECK(g_threads); + return *g_threads; +} + +void Threads::Set(const Threads& threads) { + FXL_CHECK(!g_threads); + g_threads = new Threads(); + *g_threads = threads; +} + +} // namespace blink diff --git a/common/threads.h b/common/threads.h new file mode 100644 index 0000000000000..456a5eba8ad97 --- /dev/null +++ b/common/threads.h @@ -0,0 +1,48 @@ +// Copyright 2016 The Chromium 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_COMMON_THREADS_H_ +#define FLUTTER_COMMON_THREADS_H_ + +#include "lib/fxl/tasks/task_runner.h" + +#define ASSERT_IS_PLATFORM_THREAD \ + FXL_DCHECK(::blink::Threads::Platform()->RunsTasksOnCurrentThread()); +#define ASSERT_IS_GPU_THREAD \ + FXL_DCHECK(::blink::Threads::Gpu()->RunsTasksOnCurrentThread()); +#define ASSERT_IS_UI_THREAD \ + FXL_DCHECK(::blink::Threads::UI()->RunsTasksOnCurrentThread()); +#define ASSERT_IS_IO_THREAD \ + FXL_DCHECK(::blink::Threads::IO()->RunsTasksOnCurrentThread()); + +namespace blink { + +class Threads { + public: + Threads(); + Threads(fxl::RefPtr platform, + fxl::RefPtr gpu, + fxl::RefPtr ui, + fxl::RefPtr io); + ~Threads(); + + static const fxl::RefPtr& Platform(); + static const fxl::RefPtr& Gpu(); + static const fxl::RefPtr& UI(); + static const fxl::RefPtr& IO(); + + static void Set(const Threads& settings); + + private: + static const Threads& Get(); + + fxl::RefPtr platform_; + fxl::RefPtr gpu_; + fxl::RefPtr ui_; + fxl::RefPtr io_; +}; + +} // namespace blink + +#endif // FLUTTER_COMMON_THREADS_H_ diff --git a/content_handler/BUILD.gn b/content_handler/BUILD.gn index 4778784baa643..6bc00b4e2786c 100644 --- a/content_handler/BUILD.gn +++ b/content_handler/BUILD.gn @@ -20,28 +20,23 @@ template("flutter_content_handler") { sources = [ "accessibility_bridge.cc", "accessibility_bridge.h", - "application.cc", - "application.h", - "application_runner.cc", - "application_runner.h", - "compositor_context.cc", - "compositor_context.h", - "engine.cc", - "engine.h", + "app.cc", + "app.h", + "application_controller_impl.cc", + "application_controller_impl.h", "fuchsia_font_manager.cc", "fuchsia_font_manager.h", - "isolate_configurator.cc", - "isolate_configurator.h", "main.cc", - "platform_view.cc", - "platform_view.h", + "rasterizer.cc", + "rasterizer.h", + "runtime_holder.cc", + "runtime_holder.h", + "service_protocol_hooks.cc", + "service_protocol_hooks.h", "session_connection.cc", "session_connection.h", - "surface.cc", - "surface.h", - "task_observers.cc", - "task_observers.h", - "unique_fdio_ns.h", + "vulkan_rasterizer.cc", + "vulkan_rasterizer.h", "vulkan_surface.cc", "vulkan_surface.h", "vulkan_surface_pool.cc", @@ -50,26 +45,18 @@ template("flutter_content_handler") { "vulkan_surface_producer.h", ] - # The use of these dependencies is temporary and will be moved behind the - # embedder API. - flutter_deps = [ - "$flutter_root/assets", - "$flutter_root/common", - "$flutter_root/flow", - "$flutter_root/glue", - "$flutter_root/lib/ui", - "$flutter_root/runtime", - "$flutter_root/sky/engine/platform", - "$flutter_root/third_party/txt", - "$flutter_root/vulkan", - "$flutter_root/fml", - "$flutter_root/shell/common", - "$flutter_root/shell/gpu", - ] - deps = [ "//third_party/dart/runtime/bin:libdart_builtin", "//third_party/dart/runtime/platform:libdart_platform", + "$flutter_root/assets", + "$flutter_root/common", + "$flutter_root/flow", + "$flutter_root/glue", + "$flutter_root/lib/ui", + "$flutter_root/runtime", + "$flutter_root/sky/engine/platform", + "$flutter_root/third_party/txt", + "$flutter_root/vulkan", "//garnet/public/lib/app/cpp", "//garnet/public/lib/fsl", "//garnet/public/lib/fxl", @@ -86,10 +73,8 @@ template("flutter_content_handler") { "//topaz/lib/tonic", "//topaz/public/dart-pkg/fuchsia", "//topaz/public/lib/ui/flutter/sdk_ext", - "//third_party/skia:gpu", - "//third_party/zlib:minizip", "//zircon/public/lib/trace-provider", - ] + extra_deps + flutter_deps + ] + extra_deps # The flags below are needed so that Dart's CPU profiler can walk the # C++ stack. diff --git a/content_handler/README.md b/content_handler/README.md deleted file mode 100644 index 4461e808d1a47..0000000000000 --- a/content_handler/README.md +++ /dev/null @@ -1,4 +0,0 @@ -Flutter Application Runner -========================== - -Implements the `component::ApplicationRunner` FIDL interface to launch and run mutliple Flutter applications within the same process. diff --git a/content_handler/accessibility_bridge.cc b/content_handler/accessibility_bridge.cc index f3d52f6cdbbb6..cb6f9b8e21155 100644 --- a/content_handler/accessibility_bridge.cc +++ b/content_handler/accessibility_bridge.cc @@ -2,22 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "accessibility_bridge.h" +#include "flutter/content_handler/accessibility_bridge.h" #include +#include "flutter/lib/ui/semantics/semantics_node.h" #include "lib/app/cpp/application_context.h" -#include "lib/context/fidl/context_writer.fidl.h" +#include "lib/fxl/macros.h" #include "third_party/rapidjson/rapidjson/document.h" #include "third_party/rapidjson/rapidjson/stringbuffer.h" #include "third_party/rapidjson/rapidjson/writer.h" -namespace flutter { +namespace flutter_runner { -AccessibilityBridge::AccessibilityBridge(maxwell::ContextWriterPtr writer) - : writer_(std::move(writer)) {} - -AccessibilityBridge::~AccessibilityBridge() = default; +AccessibilityBridge::AccessibilityBridge(component::ApplicationContext* context) + : writer_(context->ConnectToEnvironmentService()) {} void AccessibilityBridge::UpdateSemantics( const blink::SemanticsNodeUpdates& update) { @@ -78,4 +77,4 @@ void AccessibilityBridge::EraseUnvisitedNodes( } } -} // namespace flutter +} // namespace flutter_runner diff --git a/content_handler/accessibility_bridge.h b/content_handler/accessibility_bridge.h index dde8bfaa54c36..7ac54e754d9b6 100644 --- a/content_handler/accessibility_bridge.h +++ b/content_handler/accessibility_bridge.h @@ -2,32 +2,28 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#pragma once +#ifndef FLUTTER_CONTENT_HANDLER_ACCESSIBILITY_BRIDGE_H_ +#define FLUTTER_CONTENT_HANDLER_ACCESSIBILITY_BRIDGE_H_ #include #include "flutter/lib/ui/semantics/semantics_node.h" -#include "lib/context/fidl/context_writer.fidl.h" -#include "lib/fxl/macros.h" +#include "lib/app/cpp/application_context.h" +#include -namespace flutter { +namespace flutter_runner { // Maintain an up-to-date list of SemanticsNodes on screen, and communicate // with the Context Service. -class AccessibilityBridge final { +class AccessibilityBridge { public: - AccessibilityBridge(maxwell::ContextWriterPtr writer); - - ~AccessibilityBridge(); + explicit AccessibilityBridge(component::ApplicationContext* context); // Update the internal representation of the semantics nodes, and write the // semantics to Context Service. void UpdateSemantics(const blink::SemanticsNodeUpdates& update); private: - maxwell::ContextWriterPtr writer_; - std::map semantics_nodes_; - // Walk the semantics node tree starting at |id|, and store the id of each // visited child in |visited_nodes|. void UpdateVisitedForNodeAndChildren(const int id, @@ -37,7 +33,10 @@ class AccessibilityBridge final { // |visited_nodes|. void EraseUnvisitedNodes(const std::vector& visited_nodes); - FXL_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridge); + std::map semantics_nodes_; + modular::ContextWriterPtr writer_; }; -} // namespace flutter +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_ACCESSIBILITY_BRIDGE_H_ diff --git a/content_handler/app.cc b/content_handler/app.cc new file mode 100644 index 0000000000000..1f1bde833d2f3 --- /dev/null +++ b/content_handler/app.cc @@ -0,0 +1,174 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/content_handler/app.h" + +#include +#include + +#include "flutter/common/settings.h" +#include "flutter/common/threads.h" +#include "flutter/content_handler/fuchsia_font_manager.h" +#include "flutter/lib/ui/text/font_collection.h" +#include "flutter/sky/engine/platform/fonts/fuchsia/FontCacheFuchsia.h" +#include "lib/fsl/tasks/message_loop.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/tasks/task_runner.h" +#include "lib/icu_data/cpp/icu_data.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +namespace flutter_runner { +namespace { + +static App* g_app = nullptr; + +void QuitMessageLoop() { + fsl::MessageLoop::GetCurrent()->QuitNow(); +} + +std::string GetLabelFromURL(const std::string& url) { + size_t last_slash = url.rfind('/'); + if (last_slash == std::string::npos || last_slash + 1 == url.length()) + return url; + return url.substr(last_slash + 1); +} + +} // namespace + +App::App() { + g_app = this; + context_ = component::ApplicationContext::CreateFromStartupInfo(); + + gpu_thread_ = std::make_unique(); + io_thread_ = std::make_unique(); + + auto gpu_thread_success = gpu_thread_->Run(); + auto io_thread_success = io_thread_->Run(); + + FXL_CHECK(gpu_thread_success) << "Must be able to create the GPU thread"; + FXL_CHECK(io_thread_success) << "Must be able to create the IO thread"; + + auto ui_task_runner = fsl::MessageLoop::GetCurrent()->task_runner(); + auto gpu_task_runner = gpu_thread_->TaskRunner(); + auto io_task_runner = io_thread_->TaskRunner(); + + // Notice that the Platform and UI threads are actually the same. + blink::Threads::Set(blink::Threads(ui_task_runner, // Platform + gpu_task_runner, // GPU + ui_task_runner, // UI + io_task_runner // IO + )); + + if (!icu_data::Initialize(context_.get())) { + FXL_LOG(ERROR) << "Could not initialize ICU data."; + } + + blink::Settings settings; + settings.enable_observatory = true; + blink::Settings::Set(settings); + + fonts::FontProviderPtr font_provider( + context_->ConnectToEnvironmentService()); + if (settings.using_blink) { + blink::SetFontProvider(std::move(font_provider)); + } else { + blink::FontCollection::ForProcess().GetFontCollection()-> + SetAssetFontManager( + sk_make_sp(std::move(font_provider))); + } + + context_->outgoing_services()->AddService( + [this](fidl::InterfaceRequest request) { + runner_bindings_.AddBinding(this, std::move(request)); + }); +} + +App::~App() { + icu_data::Release(); + blink::Threads::Gpu()->PostTask(QuitMessageLoop); + blink::Threads::IO()->PostTask(QuitMessageLoop); + g_app = nullptr; +} + +App& App::Shared() { + FXL_DCHECK(g_app); + return *g_app; +} + +void App::WaitForPlatformViewIds( + std::vector* platform_view_ids) { + fxl::AutoResetWaitableEvent latch; + + blink::Threads::UI()->PostTask([this, platform_view_ids, &latch]() { + WaitForPlatformViewsIdsUIThread(platform_view_ids, &latch); + }); + + latch.Wait(); +} + +void App::WaitForPlatformViewsIdsUIThread( + std::vector* platform_view_ids, + fxl::AutoResetWaitableEvent* latch) { + for (auto it = controllers_.begin(); it != controllers_.end(); it++) { + ApplicationControllerImpl* controller = it->first; + + if (!controller) { + continue; + } + + PlatformViewInfo info; + // TODO(zra): We should create real IDs for these instead of relying on the + // address of the controller. Maybe just use the UI Isolate main port? + info.view_id = reinterpret_cast(controller); + info.isolate_id = controller->GetUIIsolateMainPort(); + info.isolate_name = controller->GetUIIsolateName(); + platform_view_ids->push_back(info); + } + latch->Signal(); +} + +void App::StartApplication( + component::ApplicationPackage application, + component::ApplicationStartupInfo startup_info, + fidl::InterfaceRequest controller) { + if (controllers_.empty()) { + // Name this process after the url of the first application being launched. + base_label_ = "flutter:" + GetLabelFromURL(startup_info.launch_info.url); + } + + std::unique_ptr impl = + std::make_unique(this, std::move(application), + std::move(startup_info), + std::move(controller)); + ApplicationControllerImpl* key = impl.get(); + controllers_.emplace(key, std::move(impl)); + + UpdateProcessLabel(); +} + +void App::Destroy(ApplicationControllerImpl* controller) { + auto it = controllers_.find(controller); + if (it == controllers_.end()) + return; + controllers_.erase(it); + UpdateProcessLabel(); +} + +void App::UpdateProcessLabel() { + std::string label; + if (controllers_.size() < 2) { + label = base_label_; + } else { + std::string suffix = " (+" + std::to_string(controllers_.size() - 1) + ")"; + if (base_label_.size() + suffix.size() <= ZX_MAX_NAME_LEN - 1) { + label = base_label_ + suffix; + } else { + label = base_label_.substr(0, ZX_MAX_NAME_LEN - 1 - suffix.size() - 3) + + "..." + suffix; + } + } + zx::process::self().set_property(ZX_PROP_NAME, label.c_str(), label.size()); +} + +} // namespace flutter_runner diff --git a/content_handler/app.h b/content_handler/app.h new file mode 100644 index 0000000000000..dc8c49927d897 --- /dev/null +++ b/content_handler/app.h @@ -0,0 +1,64 @@ +// Copyright 2016 The Chromium 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_CONTENT_HANDLER_APP_H_ +#define FLUTTER_CONTENT_HANDLER_APP_H_ + +#include +#include + +#include "flutter/content_handler/application_controller_impl.h" +#include "lib/app/cpp/application_context.h" +#include +#include "lib/fsl/threading/thread.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/synchronization/waitable_event.h" + +namespace flutter_runner { + +class App : public component::ApplicationRunner { + public: + App(); + ~App(); + + static App& Shared(); + + // |component::ApplicationRunner| implementation: + + void StartApplication( + component::ApplicationPackage application, + component::ApplicationStartupInfo startup_info, + fidl::InterfaceRequest controller) override; + + void Destroy(ApplicationControllerImpl* controller); + + struct PlatformViewInfo { + uintptr_t view_id; + int64_t isolate_id; + std::string isolate_name; + }; + + void WaitForPlatformViewIds(std::vector* platform_view_ids); + + private: + void WaitForPlatformViewsIdsUIThread( + std::vector* platform_view_ids, + fxl::AutoResetWaitableEvent* latch); + void UpdateProcessLabel(); + + std::unique_ptr context_; + std::unique_ptr gpu_thread_; + std::unique_ptr io_thread_; + fidl::BindingSet runner_bindings_; + std::unordered_map> + controllers_; + std::string base_label_; + + FXL_DISALLOW_COPY_AND_ASSIGN(App); +}; + +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_APP_H_ diff --git a/content_handler/application.cc b/content_handler/application.cc deleted file mode 100644 index 7dd2270d42317..0000000000000 --- a/content_handler/application.cc +++ /dev/null @@ -1,313 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "application.h" - -#include -#include - -#include - -#include "flutter/shell/common/switches.h" -#include "lib/fsl/vmo/file.h" -#include "lib/fsl/vmo/vector.h" -#include "lib/fxl/command_line.h" -#include "lib/fxl/synchronization/waitable_event.h" -#include "task_observers.h" - -namespace flutter { - -std::pair, std::unique_ptr> -Application::Create( - Application::Delegate& delegate, - component::ApplicationPackagePtr package, - component::ApplicationStartupInfoPtr startup_info, - f1dl::InterfaceRequest controller) { - auto thread = std::make_unique(); - std::unique_ptr application; - - fxl::AutoResetWaitableEvent latch; - thread->TaskRunner()->PostTask([&]() mutable { - application.reset(new Application(delegate, // - std::move(package), // - std::move(startup_info), // - std::move(controller) // - )); - latch.Signal(); - }); - thread->Run(); - latch.Wait(); - return {std::move(thread), std::move(application)}; -} - -static std::string DebugLabelForURL(const std::string url) { - auto found = url.rfind("/"); - if (found == std::string::npos) { - return url; - } else { - return {url, found + 1}; - } -} - -Application::Application( - Application::Delegate& delegate, - component::ApplicationPackagePtr package, - component::ApplicationStartupInfoPtr startup_info, - f1dl::InterfaceRequest - application_controller_request) - : delegate_(delegate), - debug_label_(DebugLabelForURL(startup_info->launch_info->url)), - application_controller_(this) { - application_controller_.set_error_handler([this]() { Kill(); }); - - FXL_DCHECK(fdio_ns_.is_valid()); - // ApplicationLaunchInfo::url non-optional. - auto& launch_info = startup_info->launch_info; - - // ApplicationLaunchInfo::arguments optional. - if (auto& arguments = launch_info->arguments) { - settings_ = shell::SettingsFromCommandLine( - fxl::CommandLineFromIterators(arguments->begin(), arguments->end())); - } - - // TODO: ApplicationLaunchInfo::out optional. - - // TODO: ApplicationLaunchInfo::err optional. - - // ApplicationLaunchInfo::service_request optional. - if (launch_info->directory_request) { - service_provider_bridge_.ServeDirectory( - std::move(launch_info->directory_request)); - } - - // ApplicationLaunchInfo::flat_namespace optional. - if (auto& flat_namespace = startup_info->flat_namespace) { - for (size_t i = 0; i < flat_namespace->paths->size(); ++i) { - const auto& path = flat_namespace->paths->at(i); - if (path == "/svc") { - continue; - } - - zx::channel dir = std::move(flat_namespace->directories->at(i)); - zx_handle_t dir_handle = dir.release(); - if (fdio_ns_bind(fdio_ns_.get(), path->data(), dir_handle) != ZX_OK) { - FXL_DLOG(ERROR) << "Could not bind path to namespace: " << path; - zx_handle_close(dir_handle); - } - } - } else { - FXL_DLOG(ERROR) << "There was no flat namespace."; - } - - application_directory_.reset(fdio_ns_opendir(fdio_ns_.get())); - FXL_DCHECK(application_directory_.is_valid()); - - application_assets_directory_.reset( - openat(application_directory_.get(), "pkg/data", O_RDONLY | O_DIRECTORY)); - - // TODO: ApplicationLaunchInfo::additional_services optional. - - // ApplicationPackage::data: This is legacy FLX data. Ensure that we dont have - // any. - FXL_DCHECK(!package->data) << "Legacy FLX data must not be supplied."; - - // All launch arguments have been read. Perform service binding and - // final settings configuration. The next call will be to create a view - // for this application. - - service_provider_bridge_.AddService( - std::bind(&Application::CreateShellForView, this, std::placeholders::_1)); - - component::ServiceProviderPtr outgoing_services; - outgoing_services_request_ = outgoing_services.NewRequest(); - service_provider_bridge_.set_backend(std::move(outgoing_services)); - - // Setup the application controller binding. - if (application_controller_request) { - application_controller_.Bind(std::move(application_controller_request)); - } - - application_context_ = - component::ApplicationContext::CreateFrom(std::move(startup_info)); - - settings_.enable_observatory = true; - - settings_.icu_data_path = ""; - - settings_.using_blink = false; - - settings_.assets_dir = application_assets_directory_.get(); - - settings_.script_snapshot_path = "snapshot_blob.bin"; - - settings_.log_tag = debug_label_ + std::string{"(flutter)"}; - -#ifndef NDEBUG - // Debug mode - settings_.dart_non_checked_mode = false; -#else // NDEBUG - // Release mode - settings_.dart_non_checked_mode = true; -#endif // NDEBUG - - settings_.task_observer_add = - std::bind(&CurrentMessageLoopAddAfterTaskObserver, std::placeholders::_1, - std::placeholders::_2); - - settings_.task_observer_remove = std::bind( - &CurrentMessageLoopRemoveAfterTaskObserver, std::placeholders::_1); - - AttemptVMLaunchWithCurrentSettings(settings_); -} - -Application::~Application() = default; - -void Application::AttemptVMLaunchWithCurrentSettings( - const blink::Settings& settings) const { - if (blink::DartVM::ForProcessIfInitialized()) { - return; - } - - if (!blink::DartVM::IsRunningPrecompiledCode()) { - // We will be initializing the VM lazily in this case. - return; - } - - fsl::SizedVmo dylib_vmo; - - if (!fsl::VmoFromFilenameAt( - application_assets_directory_.get() /* /pkg/data */, "libapp.so", - &dylib_vmo)) { - FXL_LOG(ERROR) << "Dylib containing VM and isolate snapshots does not " - "exist. Will not be able to launch VM."; - return; - } - - dlerror(); - - auto library_handle = dlopen_vmo(dylib_vmo.vmo().get(), RTLD_LAZY); - - if (library_handle == nullptr) { - FXL_LOG(ERROR) << "Could not open dylib: " << dlerror(); - return; - } - - auto lib = fxl::MakeRefCounted( - library_handle, // library handle - true // close the handle when done - ); - - auto symbol = [](const char* str) { - return std::string{"_"} + std::string{str}; - }; - - fxl::RefPtr vm_snapshot = - fxl::MakeRefCounted( - blink::DartSnapshotBuffer::CreateWithSymbolInLibrary( - lib, symbol(blink::DartSnapshot::kVMDataSymbol).c_str()), - blink::DartSnapshotBuffer::CreateWithSymbolInLibrary( - lib, symbol(blink::DartSnapshot::kVMInstructionsSymbol).c_str())); - - fxl::RefPtr isolate_snapshot = - fxl::MakeRefCounted( - blink::DartSnapshotBuffer::CreateWithSymbolInLibrary( - lib, symbol(blink::DartSnapshot::kIsolateDataSymbol).c_str()), - blink::DartSnapshotBuffer::CreateWithSymbolInLibrary( - lib, - symbol(blink::DartSnapshot::kIsolateInstructionsSymbol).c_str())); - - blink::DartVM::ForProcess(settings_, // - std::move(vm_snapshot), // - std::move(isolate_snapshot) // - ); - if (blink::DartVM::ForProcessIfInitialized()) { - FXL_DLOG(INFO) << "VM successfully initialized for AOT mode."; - } else { - FXL_LOG(ERROR) << "VM could not be initialized for AOT mode."; - } -} - -// |component::ApplicationController| -void Application::Kill() { - if (last_return_code_.first) { - for (auto wait_callback : wait_callbacks_) { - wait_callback(last_return_code_.second); - } - } - wait_callbacks_.clear(); - - delegate_.OnApplicationTerminate(this); - // WARNING: Don't do anything past this point as this instance may have been - // collected. -} - -// |component::ApplicationController| -void Application::Detach() { - application_controller_.set_error_handler(nullptr); -} - -// |component::ApplicationController| -void Application::Wait(const WaitCallback& callback) { - wait_callbacks_.emplace_back(std::move(callback)); -} - -// |flutter::Engine::Delegate| -void Application::OnEngineTerminate(const Engine* shell_holder) { - auto found = std::find_if(shell_holders_.begin(), shell_holders_.end(), - [shell_holder](const auto& holder) { - return holder.get() == shell_holder; - }); - - if (found == shell_holders_.end()) { - return; - } - - // We may launch multiple shell in this application. However, we will - // terminate when the last shell goes away. The error code return to the - // application controller will be the last isolate that had an error. - auto return_code = shell_holder->GetEngineReturnCode(); - if (return_code.first) { - last_return_code_ = return_code; - } - - shell_holders_.erase(found); - - if (shell_holders_.size() == 0) { - Kill(); - // WARNING: Don't do anything past this point because the delegate may have - // collected this instance via the termination callback. - } -} - -void Application::CreateShellForView( - f1dl::InterfaceRequest view_provider_request) { - shells_bindings_.AddBinding(this, std::move(view_provider_request)); -} - -// |mozart::ViewProvider| -void Application::CreateView( - f1dl::InterfaceRequest view_owner, - f1dl::InterfaceRequest) { - if (!application_context_) { - FXL_DLOG(ERROR) << "Application context was invalid when attempting to " - "create a shell for a view provider request."; - return; - } - - // This method may be called multiple times. Care must be taken to ensure that - // all arguments can be accessed or synthesized multiple times. - // TODO(chinmaygarde): Figure out how to re-create the outgoing service - // request handle. - shell_holders_.emplace(std::make_unique( - *this, // delegate - debug_label_, // thread label - *application_context_, // application context - settings_, // settings - std::move(view_owner), // view owner - fdio_ns_, // FDIO namespace - std::move(outgoing_services_request_) // outgoing request - )); -} - -} // namespace flutter diff --git a/content_handler/application.h b/content_handler/application.h deleted file mode 100644 index e4f5da105cac8..0000000000000 --- a/content_handler/application.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include -#include -#include - -#include "engine.h" -#include "flutter/common/settings.h" -#include "lib/app/cpp/application_context.h" -#include "lib/app/fidl/application_controller.fidl.h" -#include "lib/fidl/cpp/bindings/binding_set.h" -#include "lib/fsl/threading/thread.h" -#include "lib/fxl/files/unique_fd.h" -#include "lib/fxl/macros.h" -#include "lib/svc/cpp/service_provider_bridge.h" -#include "lib/ui/views/fidl/view_provider.fidl.h" -#include "unique_fdio_ns.h" - -namespace flutter { - -// Represents an instance of a Flutter application that contains one of more -// Flutter engine instances. -class Application final : public Engine::Delegate, - public component::ApplicationController, - public mozart::ViewProvider { - public: - class Delegate { - public: - virtual void OnApplicationTerminate(const Application* application) = 0; - }; - - // 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> - Create(Application::Delegate& delegate, - component::ApplicationPackagePtr package, - component::ApplicationStartupInfoPtr startup_info, - f1dl::InterfaceRequest controller); - - // Must be called on the same thread returned from the create call. The thread - // may be collected after. - ~Application(); - - private: - blink::Settings settings_; - Delegate& delegate_; - const std::string debug_label_; - UniqueFDIONS fdio_ns_ = UniqueFDIONSCreate(); - fxl::UniqueFD application_directory_; - fxl::UniqueFD application_assets_directory_; - f1dl::Binding application_controller_; - f1dl::InterfaceRequest outgoing_services_request_; - component::ServiceProviderBridge service_provider_bridge_; - std::unique_ptr application_context_; - f1dl::BindingSet shells_bindings_; - std::set> shell_holders_; - std::vector wait_callbacks_; - std::pair last_return_code_; - - Application( - Application::Delegate& delegate, - component::ApplicationPackagePtr package, - component::ApplicationStartupInfoPtr startup_info, - f1dl::InterfaceRequest controller); - - // |component::ApplicationController| - void Kill() override; - - // |component::ApplicationController| - void Detach() override; - - // |component::ApplicationController| - void Wait(const WaitCallback& callback) override; - - // |mozart::ViewProvider| - void CreateView( - f1dl::InterfaceRequest view_owner, - f1dl::InterfaceRequest services) override; - - // |flutter::Engine::Delegate| - void OnEngineTerminate(const Engine* holder) override; - - void CreateShellForView( - f1dl::InterfaceRequest view_provider_request); - - void AttemptVMLaunchWithCurrentSettings( - const blink::Settings& settings) const; - - FXL_DISALLOW_COPY_AND_ASSIGN(Application); -}; - -} // namespace flutter diff --git a/content_handler/application_controller_impl.cc b/content_handler/application_controller_impl.cc new file mode 100644 index 0000000000000..9a1b449138a1b --- /dev/null +++ b/content_handler/application_controller_impl.cc @@ -0,0 +1,148 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/content_handler/application_controller_impl.h" + +#include + +#include +#include + +#include "flutter/content_handler/app.h" +#include "flutter/content_handler/runtime_holder.h" +#include "lib/app/cpp/connect.h" +#include "lib/fsl/vmo/vector.h" +#include "lib/fxl/logging.h" + +namespace flutter_runner { + +ApplicationControllerImpl::ApplicationControllerImpl( + App* app, + component::ApplicationPackage application, + component::ApplicationStartupInfo startup_info, + fidl::InterfaceRequest controller) + : app_(app), binding_(this) { + if (controller.is_valid()) { + binding_.Bind(std::move(controller)); + binding_.set_error_handler([this] { + app_->Destroy(this); + // |this| has been deleted at this point. + }); + } + + std::vector bundle; + if (application.data) { + if (!fsl::VectorFromVmo(std::move(*application.data), &bundle)) { + FXL_LOG(ERROR) << "Failed to receive bundle."; + return; + } + } + + // TODO(jeffbrown): Decide what to do with command-line arguments and + // startup handles. + + if (startup_info.launch_info.directory_request.is_valid()) { + service_provider_bridge_.ServeDirectory( + std::move(startup_info.launch_info.directory_request)); + } + + service_provider_bridge_.AddService( + [this](fidl::InterfaceRequest request) { + view_provider_bindings_.AddBinding(this, std::move(request)); + }); + + component::ServiceProviderPtr service_provider; + auto request = service_provider.NewRequest(); + service_provider_bridge_.set_backend(std::move(service_provider)); + + fdio_ns_t* fdio_ns = SetupNamespace(&startup_info.flat_namespace); + if (fdio_ns == nullptr) { + FXL_LOG(ERROR) << "Failed to initialize namespace"; + return; + } + + url_ = startup_info.launch_info.url; + runtime_holder_.reset(new RuntimeHolder()); + runtime_holder_->SetMainIsolateShutdownCallback([this]() { Kill(); }); + runtime_holder_->Init( + fdio_ns, + component::ApplicationContext::CreateFrom(std::move(startup_info)), + std::move(request), std::move(bundle)); +} + +ApplicationControllerImpl::~ApplicationControllerImpl() = default; + +constexpr char kServiceRootPath[] = "/svc"; + +fdio_ns_t* ApplicationControllerImpl::SetupNamespace( + component::FlatNamespace* flat) { + fdio_ns_t* fdio_namespc; + zx_status_t status = fdio_ns_create(&fdio_namespc); + if (status != ZX_OK) { + FXL_LOG(ERROR) << "Failed to create namespace"; + return nullptr; + } + for (size_t i = 0; i < flat->paths->size(); ++i) { + if (flat->paths->at(i) == kServiceRootPath) { + // Ownership of /svc goes to the ApplicationContext created above. + continue; + } + zx::channel dir = std::move(flat->directories->at(i)); + zx_handle_t dir_handle = dir.release(); + const char* path = flat->paths->at(i)->data(); + status = fdio_ns_bind(fdio_namespc, path, dir_handle); + if (status != ZX_OK) { + FXL_LOG(ERROR) << "Failed to bind " << flat->paths->at(i) + << " to namespace"; + zx_handle_close(dir_handle); + fdio_ns_destroy(fdio_namespc); + return nullptr; + } + } + return fdio_namespc; +} + +void ApplicationControllerImpl::Kill() { + SendReturnCode(runtime_holder_->return_code()); + runtime_holder_.reset(); + app_->Destroy(this); + // |this| has been deleted at this point. +} + +void ApplicationControllerImpl::Detach() { + binding_.set_error_handler(fxl::Closure()); +} + +void ApplicationControllerImpl::Wait(WaitCallback callback) { + wait_callbacks_.push_back(std::move(callback)); +} + +void ApplicationControllerImpl::SendReturnCode(int32_t return_code) { + for (const auto& iter : wait_callbacks_) { + iter(return_code); + } + wait_callbacks_.clear(); +} + +void ApplicationControllerImpl::CreateView( + fidl::InterfaceRequest view_owner_request, + fidl::InterfaceRequest services) { + runtime_holder_->CreateView(url_, std::move(view_owner_request), + std::move(services)); +} + +Dart_Port ApplicationControllerImpl::GetUIIsolateMainPort() { + if (!runtime_holder_) + return ILLEGAL_PORT; + return runtime_holder_->GetUIIsolateMainPort(); +} + +std::string ApplicationControllerImpl::GetUIIsolateName() { + if (!runtime_holder_) { + return ""; + } + return runtime_holder_->GetUIIsolateName(); +} + +} // namespace flutter_runner diff --git a/content_handler/application_controller_impl.h b/content_handler/application_controller_impl.h new file mode 100644 index 0000000000000..01700f2886ffb --- /dev/null +++ b/content_handler/application_controller_impl.h @@ -0,0 +1,76 @@ +// Copyright 2016 The Chromium 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_CONTENT_HANDLER_APPLICATION_IMPL_H_ +#define FLUTTER_CONTENT_HANDLER_APPLICATION_IMPL_H_ + +#include + +#include + +#include +#include +#include + +#include "lib/fidl/cpp/binding.h" +#include "lib/fidl/cpp/binding_set.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/synchronization/waitable_event.h" +#include "lib/svc/cpp/service_provider_bridge.h" +#include "third_party/dart/runtime/include/dart_api.h" + +namespace flutter_runner { +class App; +class RuntimeHolder; + +class ApplicationControllerImpl : public component::ApplicationController, + public views_v1::ViewProvider { + public: + ApplicationControllerImpl( + App* app, + component::ApplicationPackage application, + component::ApplicationStartupInfo startup_info, + fidl::InterfaceRequest controller); + + ~ApplicationControllerImpl() override; + + // |component::ApplicationController| implementation + + void Kill() override; + void Detach() override; + void Wait(WaitCallback callback) override; + + // |views_v1::ViewProvider| implementation + + void CreateView( + fidl::InterfaceRequest view_owner_request, + fidl::InterfaceRequest services) override; + + Dart_Port GetUIIsolateMainPort(); + std::string GetUIIsolateName(); + + private: + void StartRuntimeIfReady(); + void SendReturnCode(int32_t return_code); + + fdio_ns_t* SetupNamespace(component::FlatNamespace* flat); + + App* app_; + fidl::Binding binding_; + + component::ServiceProviderBridge service_provider_bridge_; + + fidl::BindingSet view_provider_bindings_; + + std::string url_; + std::unique_ptr runtime_holder_; + + std::vector wait_callbacks_; + + FXL_DISALLOW_COPY_AND_ASSIGN(ApplicationControllerImpl); +}; + +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_APPLICATION_IMPL_H_ diff --git a/content_handler/application_runner.cc b/content_handler/application_runner.cc deleted file mode 100644 index 2d77f43cbdd45..0000000000000 --- a/content_handler/application_runner.cc +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "application_runner.h" - -#include - -#include "flutter/lib/ui/text/font_collection.h" -#include "fuchsia_font_manager.h" -#include "lib/fonts/fidl/font_provider.fidl.h" -#include "lib/icu_data/cpp/icu_data.h" - -namespace flutter { - -ApplicationRunner::ApplicationRunner(fxl::Closure on_termination_callback) - : on_termination_callback_(std::move(on_termination_callback)), - host_context_(component::ApplicationContext::CreateFromStartupInfo()) { - SetupICU(); - - SetupGlobalFonts(); - - const std::string process_label = "flutter"; - zx::process::self().set_property(ZX_PROP_NAME, process_label.c_str(), - process_label.size()); - - host_context_->outgoing_services()->AddService( - std::bind(&ApplicationRunner::RegisterApplication, this, - std::placeholders::_1)); - - active_applications_bindings_.set_empty_set_handler( - [this]() { FireTerminationCallbackIfNecessary(); }); -} - -ApplicationRunner::~ApplicationRunner() { - host_context_->outgoing_services() - ->RemoveService(); -} - -void ApplicationRunner::RegisterApplication( - f1dl::InterfaceRequest request) { - active_applications_bindings_.AddBinding(this, std::move(request)); -} - -void ApplicationRunner::StartApplication( - component::ApplicationPackagePtr package, - component::ApplicationStartupInfoPtr startup_info, - f1dl::InterfaceRequest controller) { - auto thread_application_pair = - Application::Create(*this, // delegate - std::move(package), // application pacakge - std::move(startup_info), // startup info - std::move(controller) // controller request - ); - active_applications_[thread_application_pair.second.get()] = - std::move(thread_application_pair); -} - -void ApplicationRunner::OnApplicationTerminate(const Application* application) { - active_applications_.erase(application); - FireTerminationCallbackIfNecessary(); -} - -void ApplicationRunner::SetupICU() { - if (!icu_data::Initialize(host_context_.get())) { - FXL_LOG(ERROR) << "Could not initialize ICU data."; - } -} - -void ApplicationRunner::SetupGlobalFonts() { - fonts::FontProviderPtr font_provider( - host_context_->ConnectToEnvironmentService()); - auto font_manager = - sk_make_sp(std::move(font_provider)); - blink::FontCollection::ForProcess() - .GetFontCollection() - ->SetDefaultFontManager(std::move(font_manager)); -} - -void ApplicationRunner::FireTerminationCallbackIfNecessary() { - // We have no reason to exist if: - // 1: No previously launched applications are running. - // 2: No bindings exist that may require launching more applications. - if (on_termination_callback_ && active_applications_.size() == 0 && - active_applications_bindings_.size() == 0) { - on_termination_callback_(); - } -} - -} // namespace flutter diff --git a/content_handler/application_runner.h b/content_handler/application_runner.h deleted file mode 100644 index fdf5b4420dc0f..0000000000000 --- a/content_handler/application_runner.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include -#include - -#include "application.h" -#include "lib/app/cpp/application_context.h" -#include "lib/app/fidl/application_runner.fidl.h" -#include "lib/fidl/cpp/bindings/binding_set.h" -#include "lib/fsl/tasks/message_loop.h" -#include "lib/fxl/functional/make_copyable.h" -#include "lib/fxl/macros.h" - -namespace flutter { - -// Publishes the |component::ApplicationRunner| service and runs applications on -// their own threads. -class ApplicationRunner final : public Application::Delegate, - public component::ApplicationRunner { - public: - ApplicationRunner(fxl::Closure on_termination_callback); - - ~ApplicationRunner(); - - private: - struct ActiveApplication { - std::unique_ptr thread; - std::unique_ptr application; - - ActiveApplication(std::pair, - std::unique_ptr> pair) - : thread(std::move(pair.first)), application(std::move(pair.second)) {} - - ActiveApplication() { - if (thread && application) { - thread->TaskRunner()->PostTask( - fxl::MakeCopyable([application = std::move(application)]() mutable { - application.reset(); - fsl::MessageLoop::GetCurrent()->PostQuitTask(); - })); - thread.reset(); // join - } - } - }; - - fxl::Closure on_termination_callback_; - std::unique_ptr host_context_; - f1dl::BindingSet active_applications_bindings_; - std::unordered_map - active_applications_; - - // |component::ApplicationRunner| - void StartApplication(component::ApplicationPackagePtr application, - component::ApplicationStartupInfoPtr startup_info, - f1dl::InterfaceRequest - controller) override; - - void RegisterApplication( - f1dl::InterfaceRequest request); - - void UnregisterApplication(const Application* application); - - // |Application::Delegate| - void OnApplicationTerminate(const Application* application) override; - - void SetupICU(); - - void SetupGlobalFonts(); - - void FireTerminationCallbackIfNecessary(); - - FXL_DISALLOW_COPY_AND_ASSIGN(ApplicationRunner); -}; - -} // namespace flutter diff --git a/content_handler/compositor_context.cc b/content_handler/compositor_context.cc deleted file mode 100644 index efad9ac2b9583..0000000000000 --- a/content_handler/compositor_context.cc +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "compositor_context.h" - -#include "flutter/flow/layers/layer_tree.h" -#include "flutter/glue/trace_event.h" - -namespace flutter { - -class ScopedFrame final : public flow::CompositorContext::ScopedFrame { - public: - ScopedFrame(flow::CompositorContext& context, - bool instrumentation_enabled, - SessionConnection& session_connection) - : flow::CompositorContext::ScopedFrame(context, - nullptr, - nullptr, - instrumentation_enabled), - session_connection_(session_connection) {} - - private: - SessionConnection& session_connection_; - - bool Raster(flow::LayerTree& layer_tree, bool ignore_raster_cache) override { - if (!session_connection_.has_metrics()) { - return true; - } - - { - // Preroll the Flutter layer tree. This allows Flutter to perform - // pre-paint optimizations. - TRACE_EVENT0("flutter", "Preroll"); - layer_tree.Preroll(*this, true /* ignore raster cache */); - } - - { - // Traverse the Flutter layer tree so that the necessary session ops to - // represent the frame are enqueued in the underlying session. - TRACE_EVENT0("flutter", "UpdateScene"); - layer_tree.UpdateScene(session_connection_.scene_update_context(), - session_connection_.root_node()); - } - - { - // Flush all pending session ops. - TRACE_EVENT0("flutter", "SessionPresent"); - session_connection_.Present(*this); - } - - return true; - } - - FXL_DISALLOW_COPY_AND_ASSIGN(ScopedFrame); -}; - -CompositorContext::CompositorContext( - const ui::ScenicPtr& scenic, - std::string debug_label, - zx::eventpair import_token, - OnMetricsUpdate session_metrics_did_change_callback, - fxl::Closure session_error_callback) - : debug_label_(std::move(debug_label)), - session_connection_(scenic, - debug_label_, - std::move(import_token), - std::move(session_metrics_did_change_callback), - std::move(session_error_callback)) {} - -CompositorContext::~CompositorContext() = default; - -std::unique_ptr -CompositorContext::AcquireFrame(GrContext* gr_context, - SkCanvas* canvas, - bool instrumentation_enabled) { - // TODO: The AcquireFrame interface is too broad and must be refactored to get - // rid of the context and canvas arguments as those seem to be only used for - // colorspace correctness purposes on the mobile shells. - return std::make_unique(*this, // - instrumentation_enabled, // - session_connection_ // - ); -} - -} // namespace flutter diff --git a/content_handler/compositor_context.h b/content_handler/compositor_context.h deleted file mode 100644 index a6e5429c6072c..0000000000000 --- a/content_handler/compositor_context.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include "flutter/flow/compositor_context.h" -#include "garnet/public/lib/ui/scenic/fidl/scenic.fidl-common.h" -#include "lib/fxl/macros.h" -#include "session_connection.h" - -namespace flutter { - -// Holds composition specific state and bindings specific to composition on -// Fuchsia. -class CompositorContext final : public flow::CompositorContext { - public: - CompositorContext(const ui::ScenicPtr& scenic, - std::string debug_label, - zx::eventpair import_token, - OnMetricsUpdate session_metrics_did_change_callback, - fxl::Closure session_error_callback); - - ~CompositorContext() override; - - private: - const std::string debug_label_; - SessionConnection session_connection_; - - // |flow::CompositorContext| - std::unique_ptr AcquireFrame( - GrContext* gr_context, - SkCanvas* canvas, - bool instrumentation_enabled) override; - - FXL_DISALLOW_COPY_AND_ASSIGN(CompositorContext); -}; - -} // namespace flutter diff --git a/content_handler/engine.cc b/content_handler/engine.cc deleted file mode 100644 index 3349c09bdf1af..0000000000000 --- a/content_handler/engine.cc +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "engine.h" - -#include - -#include "flutter/common/task_runners.h" -#include "flutter/fml/task_runner.h" -#include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/run_configuration.h" -#include "lib/fsl/tasks/message_loop.h" -#include "lib/fxl/functional/make_copyable.h" -#include "lib/fxl/synchronization/waitable_event.h" -#include "platform_view.h" - -#ifdef ERROR -#undef ERROR -#endif - -namespace flutter { - -Engine::Engine(Delegate& delegate, - std::string thread_label, - component::ApplicationContext& application_context, - blink::Settings settings, - f1dl::InterfaceRequest view_owner, - const UniqueFDIONS& fdio_ns, - f1dl::InterfaceRequest - outgoing_services_request) - : delegate_(delegate), - thread_label_(std::move(thread_label)), - settings_(std::move(settings)), - weak_factory_(this) { - // Launch the threads that will be used to run the shell. These threads will - // be joined in the destructor. - for (auto& thread : host_threads_) { - thread.Run(); - } - - mozart::ViewManagerPtr view_manager; - application_context.ConnectToEnvironmentService(view_manager.NewRequest()); - - zx::eventpair import_token, export_token; - if (zx::eventpair::create(0u, &import_token, &export_token) != ZX_OK) { - FXL_DLOG(ERROR) << "Could not create event pair."; - return; - } - - // Setup the session connection. - ui::ScenicPtr scenic; - view_manager->GetScenic(scenic.NewRequest()); - - // Grab the parent environent services. The platform view may want to access - // some of these services. - component::ServiceProviderPtr parent_environment_service_provider; - application_context.environment()->GetServices( - parent_environment_service_provider.NewRequest()); - - // We need to manually schedule a frame when the session metrics change. - OnMetricsUpdate on_session_metrics_change_callback = std::bind( - &Engine::OnSessionMetricsDidChange, this, std::placeholders::_1); - - fxl::Closure on_session_error_callback = std::bind(&Engine::Terminate, this); - - // Grab the accessibilty context writer that can understand the semtics tree - // on the platform view. - maxwell::ContextWriterPtr accessibility_context_writer; - application_context.ConnectToEnvironmentService( - accessibility_context_writer.NewRequest()); - - // Setup the callback that will instantiate the platform view. - shell::Shell::CreateCallback on_create_platform_view = - fxl::MakeCopyable([debug_label = thread_label_, // - parent_environment_service_provider = - std::move(parent_environment_service_provider), // - view_manager = std::ref(view_manager), // - view_owner = std::move(view_owner), // - scenic = std::move(scenic), // - accessibility_context_writer = - std::move(accessibility_context_writer), // - export_token = std::move(export_token), // - import_token = std::move(import_token), // - on_session_metrics_change_callback, // - on_session_error_callback // - ](shell::Shell& shell) mutable { - return std::make_unique( - shell, // delegate - debug_label, // debug label - shell.GetTaskRunners(), // task runners - std::move(parent_environment_service_provider), // services - view_manager, // view manager - std::move(view_owner), // view owner - std::move(scenic), // scenic - std::move(export_token), // export token - std::move(import_token), // import token - std::move( - accessibility_context_writer), // accessibility context writer - std::move(on_session_metrics_change_callback), // metrics change - std::move(on_session_error_callback) // session_error - ); - }); - - // Setup the callback that will instantiate the rasterizer. - shell::Shell::CreateCallback on_create_rasterizer = - [](shell::Shell& shell) { - return std::make_unique( - shell.GetTaskRunners() // task runners - ); - }; - - // Get the task runners from the managed threads. The current thread will be - // used as the "platform" thread. - blink::TaskRunners task_runners( - thread_label_, // Dart thread labels - fsl::MessageLoop::GetCurrent()->task_runner(), // platform - host_threads_[0].TaskRunner(), // gpu - host_threads_[1].TaskRunner(), // ui - host_threads_[2].TaskRunner() // io - ); - - settings_.root_isolate_create_callback = - std::bind(&Engine::OnMainIsolateStart, this); - - settings_.root_isolate_shutdown_callback = - std::bind([weak = weak_factory_.GetWeakPtr(), - runner = task_runners.GetPlatformTaskRunner()]() { - runner->PostTask([weak = std::move(weak)] { - if (weak) { - weak->OnMainIsolateShutdown(); - } - }); - }); - - shell_ = shell::Shell::Create( - task_runners, // host task runners - settings_, // shell launch settings - on_create_platform_view, // platform view create callback - on_create_rasterizer // rasterizer create callback - ); - - if (!shell_) { - FXL_LOG(ERROR) << "Could not launch the shell with settings: " - << settings_.ToString(); - return; - } - - // Shell has been created. Before we run the engine, setup the isolate - // configurator. - { - PlatformView* platform_view = - static_cast(shell_->GetPlatformView().get()); - auto& view = platform_view->GetMozartView(); - component::ApplicationEnvironmentPtr application_environment; - application_context.ConnectToEnvironmentService( - application_environment.NewRequest()); - - isolate_configurator_ = std::make_unique( - fdio_ns, // - view, // - std::move(application_environment), // - std::move(outgoing_services_request) // - ); - } - - // This platform does not get a separate surface platform view creation - // notification. Fire one eagerly. - shell_->GetPlatformView()->NotifyCreated(); - - // Launch the engine in the appropriate configuration. - auto run_configuration = - shell::RunConfiguration::InferFromSettings(settings_); - - shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - fxl::MakeCopyable([engine = shell_->GetEngine(), // - run_configuration = std::move(run_configuration) // - ]() mutable { - if (!engine || !engine->Run(std::move(run_configuration))) { - FXL_LOG(ERROR) << "Could not (re)launch the engine in configuration"; - } - })); - - UpdateNativeThreadLabelNames(); -} - -Engine::~Engine() { - for (const auto& thread : host_threads_) { - thread.TaskRunner()->PostTask( - []() { fsl::MessageLoop::GetCurrent()->PostQuitTask(); }); - } -} - -void Engine::UpdateNativeThreadLabelNames() const { - auto set_thread_name = [](fxl::RefPtr runner, - std::string prefix, std::string suffix) { - runner->PostTask([name = prefix + suffix]() { - zx::thread::self().set_property(ZX_PROP_NAME, name.c_str(), name.size()); - }); - }; - auto runners = shell_->GetTaskRunners(); - set_thread_name(runners.GetPlatformTaskRunner(), thread_label_, ".platform"); - set_thread_name(runners.GetUITaskRunner(), thread_label_, ".ui"); - set_thread_name(runners.GetGPUTaskRunner(), thread_label_, ".gpu"); - set_thread_name(runners.GetIOTaskRunner(), thread_label_, ".io"); -} - -std::pair Engine::GetEngineReturnCode() const { - std::pair code(false, 0); - if (!shell_) { - return code; - } - fxl::AutoResetWaitableEvent latch; - fml::TaskRunner::RunNowOrPostTask( - shell_->GetTaskRunners().GetUITaskRunner(), - [&latch, &code, engine = shell_->GetEngine()]() { - if (engine) { - code = engine->GetUIIsolateReturnCode(); - } - latch.Signal(); - }); - latch.Wait(); - return code; -} - -void Engine::OnMainIsolateStart() { - if (!isolate_configurator_ || - !isolate_configurator_->ConfigureCurrentIsolate()) { - FXL_LOG(ERROR) << "Could not configure some native embedder bindings for a " - "new root isolate."; - } -} - -void Engine::OnMainIsolateShutdown() { - Terminate(); -} - -void Engine::Terminate() { - delegate_.OnEngineTerminate(this); - // Warning. Do not do anything after this point as the delegate may have - // collected this object. -} - -void Engine::OnSessionMetricsDidChange(double device_pixel_ratio) { - if (!shell_) { - return; - } - - shell_->GetTaskRunners().GetPlatformTaskRunner()->PostTask( - [platform_view = shell_->GetPlatformView(), device_pixel_ratio]() { - if (platform_view) { - reinterpret_cast(platform_view.get()) - ->UpdateViewportMetrics(device_pixel_ratio); - } - }); -} - -} // namespace flutter diff --git a/content_handler/engine.h b/content_handler/engine.h deleted file mode 100644 index 60c0ad7c2f80d..0000000000000 --- a/content_handler/engine.h +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include "flutter/shell/common/shell.h" -#include "isolate_configurator.h" -#include "lib/app/cpp/application_context.h" -#include "lib/fsl/threading/thread.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" -#include "lib/ui/views/fidl/view_manager.fidl.h" - -namespace flutter { - -// Represents an instance of running Flutter engine along with the threads that -// host the same. -class Engine final { - public: - class Delegate { - public: - virtual void OnEngineTerminate(const Engine* holder) = 0; - }; - - Engine(Delegate& delegate, - std::string thread_label, - component::ApplicationContext& application_context, - blink::Settings settings, - f1dl::InterfaceRequest view_owner, - const UniqueFDIONS& fdio_ns, - f1dl::InterfaceRequest - outgoing_services_request); - - ~Engine(); - - // Returns the Dart return code for the root isolate if one is present. This - // call is thread safe and synchronous. This call must be made infrequently. - std::pair GetEngineReturnCode() const; - - private: - Delegate& delegate_; - const std::string thread_label_; - blink::Settings settings_; - std::array host_threads_; - std::unique_ptr isolate_configurator_; - std::unique_ptr shell_; - fxl::WeakPtrFactory weak_factory_; - - void OnMainIsolateStart(); - - void OnMainIsolateShutdown(); - - void Terminate(); - - void OnSessionMetricsDidChange(double device_pixel_ratio); - - void UpdateNativeThreadLabelNames() const; - - FXL_DISALLOW_COPY_AND_ASSIGN(Engine); -}; - -} // namespace flutter diff --git a/content_handler/fuchsia_font_manager.cc b/content_handler/fuchsia_font_manager.cc index 877c931130eb4..4e409cae94f6a 100644 --- a/content_handler/fuchsia_font_manager.cc +++ b/content_handler/fuchsia_font_manager.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "fuchsia_font_manager.h" +#include "flutter/content_handler/fuchsia_font_manager.h" #include @@ -32,14 +32,14 @@ void UnmapMemory(const void* buffer, void* context) { zx::vmar::root_self().unmap(reinterpret_cast(buffer), size); } -sk_sp MakeSkDataFromVMO(const fsl::SizedVmoTransportPtr& vmo) { - if (!fsl::SizedVmo::IsSizeValid(vmo->vmo, vmo->size) || - vmo->size > std::numeric_limits::max()) { +sk_sp MakeSkDataFromBuffer(mem::Buffer data) { + if (!fsl::SizedVmo::IsSizeValid(data.vmo, data.size) || + data.size > std::numeric_limits::max()) { return nullptr; } - uint64_t size = vmo->size; + uint64_t size = data.size; uintptr_t buffer = 0; - zx_status_t status = zx::vmar::root_self().map(0, vmo->vmo, 0, size, + zx_status_t status = zx::vmar::root_self().map(0, data.vmo, 0, size, ZX_VM_FLAG_PERM_READ, &buffer); if (status != ZX_OK) return nullptr; @@ -49,7 +49,7 @@ sk_sp MakeSkDataFromVMO(const fsl::SizedVmoTransportPtr& vmo) { fonts::FontSlant ToFontSlant(SkFontStyle::Slant slant) { return (slant == SkFontStyle::kItalic_Slant) ? fonts::FontSlant::ITALIC - : fonts::FontSlant::UPRIGHT; + : fonts::FontSlant::UPRIGHT; } } // anonymous namespace @@ -64,8 +64,7 @@ int FuchsiaFontManager::onCountFamilies() const { return 0; } -void FuchsiaFontManager::onGetFamilyName(int index, - SkString* familyName) const { +void FuchsiaFontManager::onGetFamilyName(int index, SkString* familyName) const { FXL_DCHECK(false); } @@ -88,13 +87,12 @@ SkFontStyleSet* FuchsiaFontManager::onMatchFamily( } SkTypeface* FuchsiaFontManager::onMatchFamilyStyle( - const char family_name[], - const SkFontStyle& style) const { - auto request = fonts::FontRequest::New(); - request->family = family_name; - request->weight = style.weight(); - request->width = style.width(); - request->slant = ToFontSlant(style.slant()); + const char family_name[], const SkFontStyle& style) const { + fonts::FontRequest request; + request.family = family_name; + request.weight = style.weight(); + request.width = style.width(); + request.slant = ToFontSlant(style.slant()); fonts::FontResponsePtr response; font_provider_->GetFont( @@ -102,13 +100,14 @@ SkTypeface* FuchsiaFontManager::onMatchFamilyStyle( [&response](fonts::FontResponsePtr r) { response = std::move(r); }); font_provider_.WaitForResponse(); - if (!response) { - FXL_DLOG(ERROR) << "Unable to contact the font provider. Did you run " - "Flutter in an environment that has a font manager?"; + FXL_DCHECK(response) + << "Unable to contact the font provider. Did you run " + "Flutter in an environment that has a font manager?\n"; + + if (!response) return nullptr; - } - sk_sp data = MakeSkDataFromVMO(response->data->vmo); + sk_sp data = MakeSkDataFromBuffer(std::move(response->data.buffer)); if (!data) return nullptr; @@ -128,13 +127,13 @@ SkTypeface* FuchsiaFontManager::onMatchFamilyStyleCharacter( } SkTypeface* FuchsiaFontManager::onMatchFaceStyle(const SkTypeface*, - const SkFontStyle&) const { + const SkFontStyle&) const { FXL_DCHECK(false); return nullptr; } sk_sp FuchsiaFontManager::onMakeFromData(sk_sp, - int ttcIndex) const { + int ttcIndex) const { FXL_DCHECK(false); return nullptr; } @@ -154,7 +153,7 @@ sk_sp FuchsiaFontManager::onMakeFromStreamArgs( } sk_sp FuchsiaFontManager::onMakeFromFile(const char path[], - int ttcIndex) const { + int ttcIndex) const { FXL_DCHECK(false); return nullptr; } diff --git a/content_handler/fuchsia_font_manager.h b/content_handler/fuchsia_font_manager.h index ecfb724b85878..e57d6ef76e72f 100644 --- a/content_handler/fuchsia_font_manager.h +++ b/content_handler/fuchsia_font_manager.h @@ -26,7 +26,7 @@ namespace txt { -class FuchsiaFontManager final : public SkFontMgr { +class FuchsiaFontManager : public SkFontMgr { public: FuchsiaFontManager(fonts::FontProviderPtr provider); diff --git a/content_handler/isolate_configurator.cc b/content_handler/isolate_configurator.cc deleted file mode 100644 index d085bea698b95..0000000000000 --- a/content_handler/isolate_configurator.cc +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "isolate_configurator.h" - -#include "dart-pkg/fuchsia/sdk_ext/fuchsia.h" -#include "dart-pkg/zircon/sdk_ext/handle.h" -#include "lib/tonic/converter/dart_converter.h" -#include "lib/tonic/dart_state.h" -#include "lib/tonic/logging/dart_error.h" -#include "lib/ui/flutter/sdk_ext/src/natives.h" -#include "third_party/dart/runtime/include/dart_api.h" - -namespace flutter { - -IsolateConfigurator::IsolateConfigurator( - const UniqueFDIONS& fdio_ns, - mozart::ViewPtr& view, - component::ApplicationEnvironmentPtr application_environment, - f1dl::InterfaceRequest - outgoing_services_request) - : fdio_ns_(fdio_ns), - view_(view), - application_environment_(std::move(application_environment)), - outgoing_services_request_(std::move(outgoing_services_request)) {} - -IsolateConfigurator::~IsolateConfigurator() = default; - -bool IsolateConfigurator::ConfigureCurrentIsolate() { - if (used_) { - return false; - } - used_ = true; - - BindFuchsia(); - BindZircon(); - BindDartIO(); - BindScenic(); - - return true; -} - -// |mozart::NativesDelegate| -mozart::View* IsolateConfigurator::GetMozartView() { - return view_.get(); -} - -void IsolateConfigurator::BindFuchsia() { - fuchsia::dart::Initialize(application_environment_.Unbind(), - std::move(outgoing_services_request_)); -} - -void IsolateConfigurator::BindZircon() { - // Tell dart:zircon about the FDIO namespace configured for this instance. - Dart_Handle zircon_lib = Dart_LookupLibrary(tonic::ToDart("dart:zircon")); - DART_CHECK_VALID(zircon_lib); - - Dart_Handle namespace_type = - Dart_GetType(zircon_lib, tonic::ToDart("_Namespace"), 0, nullptr); - DART_CHECK_VALID(namespace_type); - DART_CHECK_VALID( - Dart_SetField(namespace_type, // - tonic::ToDart("_namespace"), // - tonic::ToDart(reinterpret_cast(fdio_ns_.get())))); -} - -void IsolateConfigurator::BindDartIO() { - // Grab the dart:io lib. - Dart_Handle io_lib = Dart_LookupLibrary(tonic::ToDart("dart:io")); - DART_CHECK_VALID(io_lib); - - // Disable dart:io exit() - Dart_Handle embedder_config_type = - Dart_GetType(io_lib, tonic::ToDart("_EmbedderConfig"), 0, nullptr); - DART_CHECK_VALID(embedder_config_type); - DART_CHECK_VALID(Dart_SetField(embedder_config_type, - tonic::ToDart("_mayExit"), Dart_False())); - - // Tell dart:io about the FDIO namespace configured for this instance. - Dart_Handle namespace_type = - Dart_GetType(io_lib, tonic::ToDart("_Namespace"), 0, nullptr); - DART_CHECK_VALID(namespace_type); - Dart_Handle namespace_args[] = { - Dart_NewInteger(reinterpret_cast(fdio_ns_.get())), // - }; - DART_CHECK_VALID(namespace_args[0]); - DART_CHECK_VALID(Dart_Invoke(namespace_type, tonic::ToDart("_setupNamespace"), - 1, namespace_args)); -} - -void IsolateConfigurator::BindScenic() { - Dart_Handle mozart_internal = - Dart_LookupLibrary(tonic::ToDart("dart:mozart.internal")); - DART_CHECK_VALID(mozart_internal); - DART_CHECK_VALID(Dart_SetNativeResolver(mozart_internal, // - mozart::NativeLookup, // - mozart::NativeSymbol) // - ); - DART_CHECK_VALID(Dart_SetField( - mozart_internal, // - tonic::ToDart("_context"), // - tonic::DartConverter::ToDart(reinterpret_cast( - static_cast(this))))); - mozart::ViewContainerPtr view_container; - view_->GetContainer(view_container.NewRequest()); - DART_CHECK_VALID( - Dart_SetField(mozart_internal, // - tonic::ToDart("_viewContainer"), // - tonic::ToDart(zircon::dart::Handle::Create( - view_container.Unbind().TakeChannel().release())))); -} - -} // namespace flutter diff --git a/content_handler/isolate_configurator.h b/content_handler/isolate_configurator.h deleted file mode 100644 index a5da083633ee7..0000000000000 --- a/content_handler/isolate_configurator.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include "lib/app/fidl/application_environment.fidl.h" -#include "lib/fxl/macros.h" -#include "lib/ui/flutter/sdk_ext/src/natives.h" -#include "lib/ui/views/fidl/view_containers.fidl.h" -#include "lib/ui/views/fidl/views.fidl.h" -#include "unique_fdio_ns.h" - -namespace flutter { - -// Contains all the information necessary to configure a new root isolate. This -// is a single use item. The lifetime of this object must extend past that of -// the root isolate. -class IsolateConfigurator final : mozart::NativesDelegate { - public: - IsolateConfigurator( - const UniqueFDIONS& fdio_ns, - mozart::ViewPtr& view, - component::ApplicationEnvironmentPtr application_environment, - f1dl::InterfaceRequest - outgoing_services_request); - - ~IsolateConfigurator(); - - // Can be used only once and only on the UI thread with the newly created - // isolate already current. - bool ConfigureCurrentIsolate(); - - private: - bool used_ = false; - const UniqueFDIONS& fdio_ns_; - mozart::ViewPtr& view_; - component::ApplicationEnvironmentPtr application_environment_; - f1dl::InterfaceRequest outgoing_services_request_; - - // |mozart::NativesDelegate| - mozart::View* GetMozartView() override; - - void BindFuchsia(); - - void BindZircon(); - - void BindDartIO(); - - void BindScenic(); - - FXL_DISALLOW_COPY_AND_ASSIGN(IsolateConfigurator); -}; - -} // namespace flutter diff --git a/content_handler/main.cc b/content_handler/main.cc index 15b8cede5b9b2..d3eac3c81dcbf 100644 --- a/content_handler/main.cc +++ b/content_handler/main.cc @@ -1,26 +1,16 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. +// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include -#include -#include "application_runner.h" +#include "flutter/content_handler/app.h" #include "lib/fsl/tasks/message_loop.h" -int main(int argc, char const* argv[]) { +int main(int argc, const char** argv) { fsl::MessageLoop loop; - trace::TraceProvider provider(loop.async()); - FXL_DCHECK(provider.is_valid()) << "Trace provider must be valid."; - - FXL_LOG(INFO) << "Flutter application services initialized."; - flutter::ApplicationRunner runner([&loop]() { - loop.PostQuitTask(); - FXL_LOG(INFO) << "Flutter application services terminated. Good bye..."; - }); - + flutter_runner::App app; loop.Run(); - - return EXIT_SUCCESS; + return 0; } diff --git a/content_handler/platform_view.cc b/content_handler/platform_view.cc deleted file mode 100644 index 8ac41613e449b..0000000000000 --- a/content_handler/platform_view.cc +++ /dev/null @@ -1,551 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#define RAPIDJSON_HAS_STDSTRING 1 - -#include "platform_view.h" - -#include - -#include "flutter/lib/ui/window/pointer_data.h" -#include "lib/app/cpp/connect.h" -#include "third_party/rapidjson/rapidjson/document.h" -#include "third_party/rapidjson/rapidjson/stringbuffer.h" -#include "third_party/rapidjson/rapidjson/writer.h" - -namespace flutter { - -constexpr char kFlutterPlatformChannel[] = "flutter/platform"; -constexpr char kTextInputChannel[] = "flutter/textinput"; -constexpr char kKeyEventChannel[] = "flutter/keyevent"; - -PlatformView::PlatformView( - PlatformView::Delegate& delegate, - std::string debug_label, - blink::TaskRunners task_runners, - component::ServiceProviderPtr parent_environment_service_provider, - mozart::ViewManagerPtr& view_manager, - f1dl::InterfaceRequest view_owner, - ui::ScenicPtr scenic, - zx::eventpair export_token, - zx::eventpair import_token, - maxwell::ContextWriterPtr accessibility_context_writer, - OnMetricsUpdate on_session_metrics_did_change, - fxl::Closure session_error_callback) - : shell::PlatformView(delegate, std::move(task_runners)), - debug_label_(std::move(debug_label)), - view_listener_(this), - input_listener_(this), - ime_client_(this), - scenic_(std::move(scenic)), - accessibility_bridge_(std::move(accessibility_context_writer)), - surface_( - std::make_unique(scenic_, - debug_label_, - std::move(import_token), - std::move(on_session_metrics_did_change), - std::move(session_error_callback))) { - // Create the view. - view_manager->CreateView(view_.NewRequest(), // view - std::move(view_owner), // view owner - view_listener_.NewBinding(), // view listener - std::move(export_token), // export token - debug_label_ // diagnostic label - ); - - // Get the services from the created view. - component::ServiceProviderPtr service_provider; - view_->GetServiceProvider(service_provider.NewRequest()); - - // Get the input connection from the services of the view. - component::ConnectToService(service_provider.get(), - input_connection_.NewRequest()); - - // Set the input listener on the input connection. - input_connection_->SetEventListener(input_listener_.NewBinding()); - - // Access the clipboard. - component::ConnectToService(parent_environment_service_provider.get(), - clipboard_.NewRequest()); - - // Finally! Register the native platform message handlers. - RegisterPlatformMessageHandlers(); -} - -PlatformView::~PlatformView() = default; - -void PlatformView::RegisterPlatformMessageHandlers() { - platform_message_handlers_[kFlutterPlatformChannel] = - std::bind(&PlatformView::HandleFlutterPlatformChannelPlatformMessage, // - this, // - std::placeholders::_1); - platform_message_handlers_[kTextInputChannel] = - std::bind(&PlatformView::HandleFlutterTextInputChannelPlatformMessage, // - this, // - std::placeholders::_1); -} - -mozart::ViewPtr& PlatformView::GetMozartView() { - return view_; -} - -// |mozart::ViewListener| -void PlatformView::OnPropertiesChanged( - mozart::ViewPropertiesPtr properties, - const OnPropertiesChangedCallback& callback) { - UpdateViewportMetrics(properties->view_layout); - callback(); -} - -void PlatformView::UpdateViewportMetrics(const mozart::ViewLayoutPtr& layout) { - if (!layout) { - return; - } - - metrics_.size.width = layout->size->width; - metrics_.size.height = layout->size->height; - - metrics_.padding.left = layout->inset->left; - metrics_.padding.top = layout->inset->top; - metrics_.padding.right = layout->inset->right; - metrics_.padding.bottom = layout->inset->bottom; - - FlushViewportMetrics(); -} - -void PlatformView::UpdateViewportMetrics(double pixel_ratio) { - metrics_.scale = pixel_ratio; - - FlushViewportMetrics(); -} - -void PlatformView::FlushViewportMetrics() { - const auto scale = metrics_.scale; - blink::ViewportMetrics metrics = { - .device_pixel_ratio = static_cast(scale), - - .physical_width = static_cast(metrics_.size.width * scale), - .physical_height = static_cast(metrics_.size.height * scale), - - .physical_padding_top = - static_cast(metrics_.padding.top * scale), - .physical_padding_right = - static_cast(metrics_.padding.right * scale), - .physical_padding_bottom = - static_cast(metrics_.padding.bottom * scale), - .physical_padding_left = - static_cast(metrics_.padding.left * scale), - - .physical_view_inset_top = - static_cast(metrics_.view_inset.top * scale), - .physical_view_inset_right = - static_cast(metrics_.view_inset.right * scale), - .physical_view_inset_bottom = - static_cast(metrics_.view_inset.bottom * scale), - .physical_view_inset_left = - static_cast(metrics_.view_inset.left * scale), - }; - - SetViewportMetrics(metrics); -} - -// |mozart::InputMethodEditorClient| -void PlatformView::DidUpdateState(mozart::TextInputStatePtr state, - mozart::InputEventPtr event) { - rapidjson::Document document; - auto& allocator = document.GetAllocator(); - rapidjson::Value encoded_state(rapidjson::kObjectType); - encoded_state.AddMember("text", state->text.get(), allocator); - encoded_state.AddMember("selectionBase", state->selection->base, allocator); - encoded_state.AddMember("selectionExtent", state->selection->extent, - allocator); - switch (state->selection->affinity) { - case mozart::TextAffinity::UPSTREAM: - encoded_state.AddMember("selectionAffinity", - rapidjson::Value("TextAffinity.upstream"), - allocator); - break; - case mozart::TextAffinity::DOWNSTREAM: - encoded_state.AddMember("selectionAffinity", - rapidjson::Value("TextAffinity.downstream"), - allocator); - break; - } - encoded_state.AddMember("selectionIsDirectional", true, allocator); - encoded_state.AddMember("composingBase", state->composing->start, allocator); - encoded_state.AddMember("composingExtent", state->composing->end, allocator); - - rapidjson::Value args(rapidjson::kArrayType); - args.PushBack(current_text_input_client_, allocator); - args.PushBack(encoded_state, allocator); - - document.SetObject(); - document.AddMember("method", - rapidjson::Value("TextInputClient.updateEditingState"), - allocator); - document.AddMember("args", args, allocator); - - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - document.Accept(writer); - - const uint8_t* data = reinterpret_cast(buffer.GetString()); - DispatchPlatformMessage(fxl::MakeRefCounted( - kTextInputChannel, // channel - std::vector(data, data + buffer.GetSize()), // message - nullptr) // response - ); -} - -// |mozart::InputMethodEditorClient| -void PlatformView::OnAction(mozart::InputMethodAction action) { - rapidjson::Document document; - auto& allocator = document.GetAllocator(); - - rapidjson::Value args(rapidjson::kArrayType); - args.PushBack(current_text_input_client_, allocator); - - // Done is currently the only text input action defined by Flutter. - args.PushBack("TextInputAction.done", allocator); - - document.SetObject(); - document.AddMember( - "method", rapidjson::Value("TextInputClient.performAction"), allocator); - document.AddMember("args", args, allocator); - - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - document.Accept(writer); - - const uint8_t* data = reinterpret_cast(buffer.GetString()); - DispatchPlatformMessage(fxl::MakeRefCounted( - kTextInputChannel, // channel - std::vector(data, data + buffer.GetSize()), // message - nullptr) // response - ); -} - -// |mozart::InputListener| -void PlatformView::OnEvent(mozart::InputEventPtr event, - const OnEventCallback& callback) { - using Type = mozart::InputEvent::Tag; - switch (event->which()) { - case Type::POINTER: - callback(OnHandlePointerEvent(event->get_pointer())); - return; - case Type::KEYBOARD: - callback(OnHandleKeyboardEvent(event->get_keyboard())); - return; - case Type::FOCUS: - callback(OnHandleFocusEvent(event->get_focus())); - return; - case Type::__UNKNOWN__: - break; - } - - callback(false); -} - -static blink::PointerData::Change GetChangeFromPointerEventPhase( - mozart::PointerEvent::Phase phase) { - switch (phase) { - case mozart::PointerEvent::Phase::ADD: - return blink::PointerData::Change::kAdd; - case mozart::PointerEvent::Phase::HOVER: - return blink::PointerData::Change::kHover; - case mozart::PointerEvent::Phase::DOWN: - return blink::PointerData::Change::kDown; - case mozart::PointerEvent::Phase::MOVE: - return blink::PointerData::Change::kMove; - case mozart::PointerEvent::Phase::UP: - return blink::PointerData::Change::kUp; - case mozart::PointerEvent::Phase::REMOVE: - return blink::PointerData::Change::kRemove; - case mozart::PointerEvent::Phase::CANCEL: - return blink::PointerData::Change::kCancel; - default: - return blink::PointerData::Change::kCancel; - } -} - -static blink::PointerData::DeviceKind GetKindFromPointerType( - mozart::PointerEvent::Type type) { - switch (type) { - case mozart::PointerEvent::Type::TOUCH: - return blink::PointerData::DeviceKind::kTouch; - case mozart::PointerEvent::Type::MOUSE: - return blink::PointerData::DeviceKind::kMouse; - default: - return blink::PointerData::DeviceKind::kTouch; - } -} - -bool PlatformView::OnHandlePointerEvent( - const mozart::PointerEventPtr& pointer) { - blink::PointerData pointer_data; - pointer_data.time_stamp = pointer->event_time / 1000; - pointer_data.change = GetChangeFromPointerEventPhase(pointer->phase); - pointer_data.kind = GetKindFromPointerType(pointer->type); - pointer_data.device = pointer->pointer_id; - pointer_data.physical_x = pointer->x * metrics_.scale; - pointer_data.physical_y = pointer->y * metrics_.scale; - - switch (pointer_data.change) { - case blink::PointerData::Change::kDown: - down_pointers_.insert(pointer_data.device); - break; - case blink::PointerData::Change::kCancel: - case blink::PointerData::Change::kUp: - down_pointers_.erase(pointer_data.device); - break; - case blink::PointerData::Change::kMove: - if (down_pointers_.count(pointer_data.device) == 0) { - pointer_data.change = blink::PointerData::Change::kHover; - } - break; - case blink::PointerData::Change::kAdd: - if (down_pointers_.count(pointer_data.device) != 0) { - FXL_DLOG(ERROR) << "Received add event for down pointer."; - } - break; - case blink::PointerData::Change::kRemove: - if (down_pointers_.count(pointer_data.device) != 0) { - FXL_DLOG(ERROR) << "Received remove event for down pointer."; - } - break; - case blink::PointerData::Change::kHover: - if (down_pointers_.count(pointer_data.device) != 0) { - FXL_DLOG(ERROR) << "Received hover event for down pointer."; - } - break; - } - - auto packet = std::make_unique(1); - packet->SetPointerData(0, pointer_data); - DispatchPointerDataPacket(std::move(packet)); - return true; -} - -bool PlatformView::OnHandleKeyboardEvent( - const mozart::KeyboardEventPtr& keyboard) { - const char* type = nullptr; - if (keyboard->phase == mozart::KeyboardEvent::Phase::PRESSED) { - type = "keydown"; - } else if (keyboard->phase == mozart::KeyboardEvent::Phase::REPEAT) { - type = "keydown"; // TODO change this to keyrepeat - } else if (keyboard->phase == mozart::KeyboardEvent::Phase::RELEASED) { - type = "keyup"; - } - - if (type == nullptr) { - FXL_DLOG(ERROR) << "Unknown key event phase."; - return false; - } - - rapidjson::Document document; - auto& allocator = document.GetAllocator(); - document.SetObject(); - document.AddMember("type", rapidjson::Value(type, strlen(type)), allocator); - document.AddMember("keymap", rapidjson::Value("fuchsia"), allocator); - document.AddMember("hidUsage", keyboard->hid_usage, allocator); - document.AddMember("codePoint", keyboard->code_point, allocator); - document.AddMember("modifiers", keyboard->modifiers, allocator); - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - document.Accept(writer); - - const uint8_t* data = reinterpret_cast(buffer.GetString()); - DispatchPlatformMessage(fxl::MakeRefCounted( - kKeyEventChannel, // channel - std::vector(data, data + buffer.GetSize()), // data - nullptr) // response - ); - - return true; -} - -bool PlatformView::OnHandleFocusEvent(const mozart::FocusEventPtr& focus) { - if (!focus->focused && current_text_input_client_ != 0) { - current_text_input_client_ = 0; - if (ime_) { - ime_->Hide(); - ime_ = nullptr; - } - if (ime_client_.is_bound()) { - ime_client_.Unbind(); - } - return true; - } - return false; -} - -// |shell::PlatformView| -std::unique_ptr PlatformView::CreateRenderingSurface() { - // This platform does not repeatly lose and gain a surface connection. So the - // surface is setup once during platform view setup and and returned to the - // shell on the initial (and only) |NotifyCreated| call. - return std::move(surface_); -} - -// |shell::PlatformView| -void PlatformView::HandlePlatformMessage( - fxl::RefPtr message) { - if (!message) { - return; - } - auto found = platform_message_handlers_.find(message->channel()); - if (found == platform_message_handlers_.end()) { - FXL_DLOG(ERROR) - << "Platform view received message on channel '" << message->channel() - << "' with no registed handler. And empty response will be generated. " - "Please implement the native message handler."; - PlatformView::HandlePlatformMessage(std::move(message)); - return; - } - found->second(std::move(message)); -} - -// |shell::PlatformView| -void PlatformView::UpdateSemantics(blink::SemanticsNodeUpdates update) { - accessibility_bridge_.UpdateSemantics(update); -} - -// Channel handler for kFlutterPlatformChannel -void PlatformView::HandleFlutterPlatformChannelPlatformMessage( - fxl::RefPtr message) { - FXL_DCHECK(message->channel() == kFlutterPlatformChannel); - const auto& data = message->data(); - rapidjson::Document document; - document.Parse(reinterpret_cast(data.data()), data.size()); - if (document.HasParseError() || !document.IsObject()) { - return; - } - - auto root = document.GetObject(); - auto method = root.FindMember("method"); - if (method == root.MemberEnd() || !method->value.IsString()) { - return; - } - - fxl::RefPtr response = message->response(); - if (method->value == "Clipboard.setData") { - auto text = root["args"]["text"].GetString(); - clipboard_->Push(text); - response->CompleteEmpty(); - } else if (method->value == "Clipboard.getData") { - clipboard_->Peek([response](const f1dl::String& text) { - rapidjson::StringBuffer json_buffer; - rapidjson::Writer writer(json_buffer); - writer.StartArray(); - writer.StartObject(); - writer.Key("text"); - writer.String(text); - writer.EndObject(); - writer.EndArray(); - std::string result = json_buffer.GetString(); - response->Complete(std::vector{result.begin(), result.end()}); - }); - } else { - response->CompleteEmpty(); - } -} - -// Channel handler for kTextInputChannel -void PlatformView::HandleFlutterTextInputChannelPlatformMessage( - fxl::RefPtr message) { - FXL_DCHECK(message->channel() == kTextInputChannel); - const auto& data = message->data(); - rapidjson::Document document; - document.Parse(reinterpret_cast(data.data()), data.size()); - if (document.HasParseError() || !document.IsObject()) { - return; - } - auto root = document.GetObject(); - auto method = root.FindMember("method"); - if (method == root.MemberEnd() || !method->value.IsString()) { - return; - } - - if (method->value == "TextInput.show") { - if (ime_) { - ime_->Show(); - } - } else if (method->value == "TextInput.hide") { - if (ime_) { - ime_->Hide(); - } - } else if (method->value == "TextInput.setClient") { - current_text_input_client_ = 0; - if (ime_client_.is_bound()) - ime_client_.Unbind(); - ime_ = nullptr; - - auto args = root.FindMember("args"); - if (args == root.MemberEnd() || !args->value.IsArray() || - args->value.Size() != 2) - return; - const auto& configuration = args->value[1]; - if (!configuration.IsObject()) { - return; - } - // TODO(abarth): Read the keyboard type from the configuration. - current_text_input_client_ = args->value[0].GetInt(); - mozart::TextInputStatePtr state = mozart::TextInputState::New(); - state->text = std::string(); - state->selection = mozart::TextSelection::New(); - state->composing = mozart::TextRange::New(); - input_connection_->GetInputMethodEditor( - mozart::KeyboardType::TEXT, mozart::InputMethodAction::DONE, - std::move(state), ime_client_.NewBinding(), ime_.NewRequest()); - } else if (method->value == "TextInput.setEditingState") { - if (ime_) { - auto args_it = root.FindMember("args"); - if (args_it == root.MemberEnd() || !args_it->value.IsObject()) { - return; - } - const auto& args = args_it->value; - mozart::TextInputStatePtr state = mozart::TextInputState::New(); - state->selection = mozart::TextSelection::New(); - state->composing = mozart::TextRange::New(); - // TODO(abarth): Deserialize state. - auto text = args.FindMember("text"); - if (text != args.MemberEnd() && text->value.IsString()) - state->text = text->value.GetString(); - auto selection_base = args.FindMember("selectionBase"); - if (selection_base != args.MemberEnd() && selection_base->value.IsInt()) - state->selection->base = selection_base->value.GetInt(); - auto selection_extent = args.FindMember("selectionExtent"); - if (selection_extent != args.MemberEnd() && - selection_extent->value.IsInt()) - state->selection->extent = selection_extent->value.GetInt(); - auto selection_affinity = args.FindMember("selectionAffinity"); - if (selection_affinity != args.MemberEnd() && - selection_affinity->value.IsString() && - selection_affinity->value == "TextAffinity.upstream") - state->selection->affinity = mozart::TextAffinity::UPSTREAM; - else - state->selection->affinity = mozart::TextAffinity::DOWNSTREAM; - // We ignore selectionIsDirectional because that concept doesn't exist on - // Fuchsia. - auto composing_base = args.FindMember("composingBase"); - if (composing_base != args.MemberEnd() && composing_base->value.IsInt()) - state->composing->start = composing_base->value.GetInt(); - auto composing_extent = args.FindMember("composingExtent"); - if (composing_extent != args.MemberEnd() && - composing_extent->value.IsInt()) - state->composing->end = composing_extent->value.GetInt(); - ime_->SetState(std::move(state)); - } - } else if (method->value == "TextInput.clearClient") { - current_text_input_client_ = 0; - if (ime_client_.is_bound()) - ime_client_.Unbind(); - ime_ = nullptr; - } else { - FXL_DLOG(ERROR) << "Unknown " << message->channel() << " method " - << method->value.GetString(); - } -} - -} // namespace flutter diff --git a/content_handler/platform_view.h b/content_handler/platform_view.h deleted file mode 100644 index 9888d061352bb..0000000000000 --- a/content_handler/platform_view.h +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include -#include - -#include "accessibility_bridge.h" -#include "flutter/lib/ui/window/viewport_metrics.h" -#include "flutter/shell/common/platform_view.h" -#include "lib/clipboard/fidl/clipboard.fidl.h" -#include "lib/fidl/cpp/bindings/binding.h" -#include "lib/fxl/macros.h" -#include "lib/ui/input/fidl/input_connection.fidl.h" -#include "lib/ui/views/fidl/view_manager.fidl.h" -#include "lib/ui/views/fidl/views.fidl.h" -#include "surface.h" - -namespace flutter { - -// The per engine component residing on the platform thread is responsible for -// all platform specific integrations. -class PlatformView final : public shell::PlatformView, - public mozart::ViewListener, - public mozart::InputMethodEditorClient, - public mozart::InputListener { - public: - PlatformView( - PlatformView::Delegate& delegate, - std::string debug_label, - blink::TaskRunners task_runners, - component::ServiceProviderPtr parent_environment_service_provider, - mozart::ViewManagerPtr& view_manager, - f1dl::InterfaceRequest view_owner, - ui::ScenicPtr scenic, - zx::eventpair export_token, - zx::eventpair import_token, - maxwell::ContextWriterPtr accessibility_context_writer, - OnMetricsUpdate on_session_metrics_did_change, - fxl::Closure session_error_callback); - - ~PlatformView(); - - void UpdateViewportMetrics(double pixel_ratio); - - mozart::ViewPtr& GetMozartView(); - - private: - const std::string debug_label_; - mozart::ViewPtr view_; - f1dl::Binding view_listener_; - mozart::InputConnectionPtr input_connection_; - f1dl::Binding input_listener_; - int current_text_input_client_ = 0; - f1dl::Binding ime_client_; - mozart::InputMethodEditorPtr ime_; - modular::ClipboardPtr clipboard_; - ui::ScenicPtr scenic_; - AccessibilityBridge accessibility_bridge_; - std::unique_ptr surface_; - blink::LogicalMetrics metrics_; - std::set down_pointers_; - std::map< - std::string /* channel */, - std::function /* message */)> /* handler */> - platform_message_handlers_; - - void RegisterPlatformMessageHandlers(); - - void UpdateViewportMetrics(const mozart::ViewLayoutPtr& layout); - - void FlushViewportMetrics(); - - // |mozart::ViewListener| - void OnPropertiesChanged( - mozart::ViewPropertiesPtr properties, - const OnPropertiesChangedCallback& callback) override; - - // |mozart::InputMethodEditorClient| - void DidUpdateState(mozart::TextInputStatePtr state, - mozart::InputEventPtr event) override; - - // |mozart::InputMethodEditorClient| - void OnAction(mozart::InputMethodAction action) override; - - // |mozart::InputListener| - void OnEvent(mozart::InputEventPtr event, - const OnEventCallback& callback) override; - - bool OnHandlePointerEvent(const mozart::PointerEventPtr& pointer); - - bool OnHandleKeyboardEvent(const mozart::KeyboardEventPtr& keyboard); - - bool OnHandleFocusEvent(const mozart::FocusEventPtr& focus); - - // |shell::PlatformView| - std::unique_ptr CreateRenderingSurface() override; - - // |shell::PlatformView| - void HandlePlatformMessage( - fxl::RefPtr message) override; - - // |shell::PlatformView| - void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - - // Channel handler for kFlutterPlatformChannel - void HandleFlutterPlatformChannelPlatformMessage( - fxl::RefPtr message); - - // Channel handler for kTextInputChannel - void HandleFlutterTextInputChannelPlatformMessage( - fxl::RefPtr message); - - FXL_DISALLOW_COPY_AND_ASSIGN(PlatformView); -}; - -} // namespace flutter diff --git a/content_handler/rasterizer.cc b/content_handler/rasterizer.cc new file mode 100644 index 0000000000000..b720809b17a45 --- /dev/null +++ b/content_handler/rasterizer.cc @@ -0,0 +1,19 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/content_handler/rasterizer.h" +#include "flutter/content_handler/vulkan_rasterizer.h" + +namespace flutter_runner { + +Rasterizer::~Rasterizer() = default; + +std::unique_ptr Rasterizer::Create() { + auto vulkan_rasterizer = std::make_unique(); + FXL_CHECK(vulkan_rasterizer) + << "The vulkan rasterizer must be correctly initialized."; + return vulkan_rasterizer; +} + +} // namespace flutter_runner diff --git a/content_handler/rasterizer.h b/content_handler/rasterizer.h new file mode 100644 index 0000000000000..398f262a568cd --- /dev/null +++ b/content_handler/rasterizer.h @@ -0,0 +1,35 @@ +// Copyright 2016 The Chromium 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_CONTENT_HANDLER_RASTERIZER_H_ +#define FLUTTER_CONTENT_HANDLER_RASTERIZER_H_ + +#include + +#include + +#include "flutter/flow/layers/layer_tree.h" +#include "lib/fxl/functional/closure.h" +#include "lib/fxl/macros.h" + +namespace flutter_runner { + +class Rasterizer { + public: + virtual ~Rasterizer(); + + static std::unique_ptr Create(); + + virtual void SetScene( + fidl::InterfaceHandle mozart, + zx::eventpair import_token, + fxl::Closure metrics_changed_callback) = 0; + + virtual void Draw(std::unique_ptr layer_tree, + fxl::Closure callback) = 0; +}; + +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_RASTERIZER_H_ diff --git a/content_handler/runtime_holder.cc b/content_handler/runtime_holder.cc new file mode 100644 index 0000000000000..421731b9691d0 --- /dev/null +++ b/content_handler/runtime_holder.cc @@ -0,0 +1,911 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/content_handler/runtime_holder.h" + +#include +#include +#include +#include +#include + +#include "dart-pkg/zircon/sdk_ext/handle.h" +#include "flutter/assets/zip_asset_store.h" +#include "flutter/common/threads.h" +#include "flutter/content_handler/accessibility_bridge.h" +#include "flutter/content_handler/rasterizer.h" +#include "flutter/content_handler/service_protocol_hooks.h" +#include "flutter/lib/snapshot/snapshot.h" +#include "flutter/lib/ui/window/pointer_data_packet.h" +#include "flutter/runtime/asset_font_selector.h" +#include "flutter/runtime/dart_controller.h" +#include "flutter/runtime/dart_init.h" +#include "flutter/runtime/runtime_init.h" +#include "lib/app/cpp/connect.h" +#include "lib/fsl/vmo/vector.h" +#include "lib/fxl/files/path.h" +#include "lib/fxl/files/unique_fd.h" +#include "lib/fxl/functional/make_copyable.h" +#include "lib/fxl/logging.h" +#include "lib/fxl/time/time_delta.h" +#include "lib/tonic/logging/dart_error.h" +#include "lib/zip/create_unzipper.h" +#include "third_party/dart/runtime/include/dart_api.h" +#include "third_party/rapidjson/rapidjson/document.h" +#include "third_party/rapidjson/rapidjson/stringbuffer.h" +#include "third_party/rapidjson/rapidjson/writer.h" + +using tonic::DartConverter; +using tonic::ToDart; + +namespace flutter_runner { +namespace { + +constexpr char kKernelKey[] = "kernel_blob.bin"; +constexpr char kSnapshotKey[] = "snapshot_blob.bin"; +constexpr char kDylibKey[] = "libapp.so"; +constexpr char kAssetChannel[] = "flutter/assets"; +constexpr char kKeyEventChannel[] = "flutter/keyevent"; +constexpr char kTextInputChannel[] = "flutter/textinput"; +constexpr char kFlutterPlatformChannel[] = "flutter/platform"; +constexpr char kFuchsiaPackageResourceDirectory[] = "pkg/data"; +constexpr char kDartPkgContentsKey[] = "dart-pkg/contents"; + +void SetThreadName(fxl::RefPtr runner, std::string name) { + runner->PostTask([name]() { + zx::thread::self().set_property(ZX_PROP_NAME, name.c_str(), name.size()); + Dart_SetThreadName(name.c_str()); + }); +} + +blink::PointerData::Change GetChangeFromPointerEventPhase( + input::PointerEventPhase phase) { + switch (phase) { + case input::PointerEventPhase::ADD: + return blink::PointerData::Change::kAdd; + case input::PointerEventPhase::HOVER: + return blink::PointerData::Change::kHover; + case input::PointerEventPhase::DOWN: + return blink::PointerData::Change::kDown; + case input::PointerEventPhase::MOVE: + return blink::PointerData::Change::kMove; + case input::PointerEventPhase::UP: + return blink::PointerData::Change::kUp; + case input::PointerEventPhase::REMOVE: + return blink::PointerData::Change::kRemove; + case input::PointerEventPhase::CANCEL: + return blink::PointerData::Change::kCancel; + default: + return blink::PointerData::Change::kCancel; + } +} + +blink::PointerData::DeviceKind GetKindFromPointerType( + input::PointerEventType type) { + switch (type) { + case input::PointerEventType::TOUCH: + return blink::PointerData::DeviceKind::kTouch; + case input::PointerEventType::MOUSE: + return blink::PointerData::DeviceKind::kMouse; + default: + return blink::PointerData::DeviceKind::kTouch; + } +} + +} // namespace + +RuntimeHolder::RuntimeHolder() + : view_listener_binding_(this), + input_listener_binding_(this), + text_input_binding_(this), + weak_factory_(this) {} + +RuntimeHolder::~RuntimeHolder() { + blink::Threads::Gpu()->PostTask( + fxl::MakeCopyable([rasterizer = std::move(rasterizer_)](){ + // Deletes rasterizer. + })); +} + +void RuntimeHolder::Init( + fdio_ns_t* namespc, + std::unique_ptr context, + fidl::InterfaceRequest outgoing_services, + std::vector bundle) { + FXL_DCHECK(!rasterizer_); + rasterizer_ = Rasterizer::Create(); + FXL_DCHECK(rasterizer_); + + namespc_ = namespc; + dirfd_ = fdio_ns_opendir(namespc); + if (dirfd_ == -1) { + FXL_LOG(ERROR) << "Failed to get fd for namespace"; + return; + } + context_ = std::move(context); + outgoing_services_ = std::move(outgoing_services); + + context_->ConnectToEnvironmentService(view_manager_.NewRequest()); + + // TODO(zarah): remove bundle entirely once flx is removed. + InitRootBundle(std::move(bundle)); + + const uint8_t* vm_snapshot_data; + const uint8_t* vm_snapshot_instr; + const uint8_t* default_isolate_snapshot_data; + const uint8_t* default_isolate_snapshot_instr; + if (!Dart_IsPrecompiledRuntime()) { + vm_snapshot_data = ::kDartVmSnapshotData; + vm_snapshot_instr = ::kDartVmSnapshotInstructions; + default_isolate_snapshot_data = ::kDartIsolateCoreSnapshotData; + default_isolate_snapshot_instr = ::kDartIsolateCoreSnapshotInstructions; + } else { + std::vector dylib_blob; + if (!GetAssetAsBuffer(kDylibKey, &dylib_blob)) { + FXL_LOG(ERROR) << "Failed to extract app dylib"; + return; + } + + fsl::SizedVmo dylib_vmo; + if (!fsl::VmoFromVector(dylib_blob, &dylib_vmo)) { + FXL_LOG(ERROR) << "Failed to load app dylib"; + return; + } + + dlerror(); + dylib_handle_ = dlopen_vmo(dylib_vmo.vmo().get(), RTLD_LAZY); + if (dylib_handle_ == nullptr) { + FXL_LOG(ERROR) << "dlopen failed: " << dlerror(); + return; + } + vm_snapshot_data = reinterpret_cast( + dlsym(dylib_handle_, "_kDartVmSnapshotData")); + vm_snapshot_instr = reinterpret_cast( + dlsym(dylib_handle_, "_kDartVmSnapshotInstructions")); + default_isolate_snapshot_data = reinterpret_cast( + dlsym(dylib_handle_, "_kDartIsolateSnapshotData")); + default_isolate_snapshot_instr = reinterpret_cast( + dlsym(dylib_handle_, "_kDartIsolateSnapshotInstructions")); + } + + // TODO(rmacnak): We should generate the AOT vm snapshot separately from + // each app so we can initialize before receiving the first app bundle. + static bool first_app = true; + if (first_app) { + first_app = false; + blink::InitRuntime(vm_snapshot_data, vm_snapshot_instr, + default_isolate_snapshot_data, + default_isolate_snapshot_instr, + /* bundle_path = */ ""); + + // This has to happen after the Dart runtime is initialized. + SetThreadName(blink::Threads::UI(), "ui"); + SetThreadName(blink::Threads::Gpu(), "gpu"); + SetThreadName(blink::Threads::IO(), "io"); + + blink::SetRegisterNativeServiceProtocolExtensionHook( + ServiceProtocolHooks::RegisterHooks); + } + + accessibility_bridge_ = std::make_unique(context_.get()); +} + +void RuntimeHolder::CreateView( + const std::string& script_uri, + fidl::InterfaceRequest view_owner_request, + fidl::InterfaceRequest services) { + if (view_listener_binding_.is_bound()) { + // TODO(jeffbrown): Refactor this to support multiple view instances + // sharing the same underlying root bundle (but with different runtimes). + FXL_LOG(ERROR) << "The view has already been created."; + return; + } + + std::vector kernel; + std::vector snapshot; + bool maybe_running_from_source = false; + if (!Dart_IsPrecompiledRuntime()) { + if (!GetAssetAsBuffer(kKernelKey, &kernel) && + !GetAssetAsBuffer(kSnapshotKey, &snapshot)) { + maybe_running_from_source = true; + FXL_LOG(INFO) << "No kernel or snapshot in root bundle."; + } + } + + // Create the view. + zx::eventpair import_token, export_token; + zx_status_t status = zx::eventpair::create(0u, &import_token, &export_token); + if (status != ZX_OK) { + FXL_LOG(ERROR) << "Could not create an event pair."; + return; + } + views_v1::ViewListenerPtr view_listener; + view_listener_binding_.Bind(view_listener.NewRequest()); + view_manager_->CreateView(view_.NewRequest(), // view + std::move(view_owner_request), // view owner + std::move(view_listener), // view listener + std::move(export_token), // export token + script_uri // diagnostic label + ); + component::ServiceProviderPtr view_services; + view_->GetServiceProvider(view_services.NewRequest()); + + // Listen for input events. + ConnectToService(view_services.get(), input_connection_.NewRequest()); + input::InputListenerPtr input_listener; + input_listener_binding_.Bind(input_listener.NewRequest()); + input_connection_->SetEventListener(std::move(input_listener)); + + // Setup the session. + fidl::InterfaceHandle scenic; + view_manager_->GetScenic(scenic.NewRequest()); + + blink::Threads::Gpu()->PostTask(fxl::MakeCopyable([ + rasterizer = rasterizer_.get(), // + scenic = std::move(scenic), // + import_token = std::move(import_token), // + weak_runtime_holder = GetWeakPtr() + ]() mutable { + ASSERT_IS_GPU_THREAD; + rasterizer->SetScene( + std::move(scenic), std::move(import_token), + // TODO(MZ-222): Ideally we would immediately redraw the previous layer + // tree when the metrics change since there's no need to rerecord it. + // However, we want to make sure there's only one outstanding frame. + // We should improve the frame scheduling so that the rasterizer thread + // can self-schedule re-rasterization. + [weak_runtime_holder] { + // This is on the GPU thread thread. Post to the Platform/UI + // thread for the completion callback. + ASSERT_IS_GPU_THREAD; + blink::Threads::Platform()->PostTask([weak_runtime_holder]() { + // On the Platform/UI thread. + ASSERT_IS_UI_THREAD; + if (weak_runtime_holder) { + weak_runtime_holder->OnRedrawFrame(); + } + }); + }); + })); + runtime_ = blink::RuntimeController::Create(this); + + const uint8_t* isolate_snapshot_data; + const uint8_t* isolate_snapshot_instr; + if (!Dart_IsPrecompiledRuntime()) { + isolate_snapshot_data = ::kDartIsolateCoreSnapshotData; + isolate_snapshot_instr = ::kDartIsolateCoreSnapshotInstructions; + } else { + isolate_snapshot_data = reinterpret_cast( + dlsym(dylib_handle_, "_kDartIsolateSnapshotData")); + isolate_snapshot_instr = reinterpret_cast( + dlsym(dylib_handle_, "_kDartIsolateSnapshotInstructions")); + } + runtime_->CreateDartController(script_uri, isolate_snapshot_data, + isolate_snapshot_instr, dirfd_); + + runtime_->SetViewportMetrics(viewport_metrics_); + + if (Dart_IsPrecompiledRuntime()) { + runtime_->dart_controller()->RunFromPrecompiledSnapshot(); + } else if (!kernel.empty()) { + runtime_->dart_controller()->RunFromKernel(std::move(kernel)); + } else if (maybe_running_from_source) { + std::vector data; + if (!GetAssetAsBuffer(kDartPkgContentsKey, &data)) { + FXL_LOG(ERROR) << "Contents file not found for " << script_uri; + return; + } + std::string package_name(data.begin(), data.end()); + std::string main_dart = "pkg/data/dart-pkg/" + package_name + "/lib/main.dart"; + FXL_LOG(INFO) << "Running from source with entrypoint: '" << main_dart + << "'"; + runtime_->dart_controller()->RunFromSource(main_dart, "pkg/data/dart-pkg/.packages"); + } else { + runtime_->dart_controller()->RunFromScriptSnapshot(snapshot.data(), + snapshot.size()); + } + + runtime_->dart_controller()->dart_state()->SetReturnCodeCallback( + [this](int32_t return_code) { return_code_ = return_code; }); +} + +Dart_Port RuntimeHolder::GetUIIsolateMainPort() { + if (!runtime_) + return ILLEGAL_PORT; + return runtime_->GetMainPort(); +} + +void RuntimeHolder::DidShutdownMainIsolate() { + if (main_isolate_shutdown_callback_) { + main_isolate_shutdown_callback_(); + } +} + +void RuntimeHolder::SetMainIsolateShutdownCallback( + std::function callback) { + main_isolate_shutdown_callback_ = callback; +} + +std::string RuntimeHolder::GetUIIsolateName() { + if (!runtime_) { + return ""; + } + return runtime_->GetIsolateName(); +} + +std::string RuntimeHolder::DefaultRouteName() { + return "/"; +} + +void RuntimeHolder::ScheduleFrame(bool regenerate_layer_tree) { + ASSERT_IS_UI_THREAD; + // TODO(mravn): We assume regenerate_layer_tree is true (and thus ignore + // that we may be able to reuse the current layer tree.) + if (!frame_scheduled_) { + frame_scheduled_ = true; + if (!frame_outstanding_) + PostBeginFrame(); + } +} + +void RuntimeHolder::Render(std::unique_ptr layer_tree) { + if (!frame_outstanding_ || frame_rendering_) { + // TODO(MZ-193): We probably shouldn't be discarding the layer tree here. + // But then, Flutter shouldn't be calling Render() if we didn't call + // BeginFrame(). + return; // Spurious. + } + + frame_rendering_ = true; + + layer_tree->set_construction_time(fxl::TimePoint::Now() - + last_begin_frame_time_); + layer_tree->set_frame_size(SkISize::Make(viewport_metrics_.physical_width, + viewport_metrics_.physical_height)); + layer_tree->set_device_pixel_ratio(viewport_metrics_.device_pixel_ratio); + + // We are on the Platform/UI thread. Post to the GPU thread to render. + ASSERT_IS_PLATFORM_THREAD; + blink::Threads::Gpu()->PostTask(fxl::MakeCopyable([ + rasterizer = rasterizer_.get(), // + layer_tree = std::move(layer_tree), // + weak_runtime_holder = GetWeakPtr() // + ]() mutable { + // On the GPU Thread. + ASSERT_IS_GPU_THREAD; + rasterizer->Draw(std::move(layer_tree), [weak_runtime_holder]() { + // This is on the GPU thread thread. Post to the Platform/UI thread + // for the completion callback. + ASSERT_IS_GPU_THREAD; + blink::Threads::Platform()->PostTask([weak_runtime_holder]() { + // On the Platform/UI thread. + ASSERT_IS_UI_THREAD; + if (weak_runtime_holder) { + weak_runtime_holder->frame_rendering_ = false; + weak_runtime_holder->OnFrameComplete(); + } + }); + }); + })); +} + +void RuntimeHolder::UpdateSemantics(blink::SemanticsNodeUpdates update) { + accessibility_bridge_->UpdateSemantics(update); +} + +void RuntimeHolder::HandlePlatformMessage( + fxl::RefPtr message) { + if (message->channel() == kAssetChannel) { + if (HandleAssetPlatformMessage(message.get())) + return; + } else if (message->channel() == kTextInputChannel) { + if (HandleTextInputPlatformMessage(message.get())) + return; + } else if (message->channel() == kFlutterPlatformChannel) { + if (HandleFlutterPlatformMessage(message.get())) + return; + } + if (auto response = message->response()) + response->CompleteEmpty(); +} + +void RuntimeHolder::DidCreateMainIsolate(Dart_Isolate isolate) { + if (asset_provider_) { + blink::AssetFontSelector::Install(asset_provider_); + } else if (asset_store_) { + blink::AssetFontSelector::Install(asset_store_); + } + InitDartIoInternal(); + InitFuchsia(); + InitZircon(); + InitScenicInternal(); +} + +void RuntimeHolder::InitDartIoInternal() { + Dart_Handle io_lib = Dart_LookupLibrary(ToDart("dart:io")); + + // Set up the namespace. + Dart_Handle namespace_type = + Dart_GetType(io_lib, ToDart("_Namespace"), 0, nullptr); + DART_CHECK_VALID(namespace_type); + Dart_Handle namespace_args[1]; + namespace_args[0] = Dart_NewInteger(reinterpret_cast(namespc_)); + DART_CHECK_VALID(namespace_args[0]); + DART_CHECK_VALID(Dart_Invoke(namespace_type, ToDart("_setupNamespace"), 1, + namespace_args)); + + // Disable dart:io exit() + Dart_Handle embedder_config_type = + Dart_GetType(io_lib, ToDart("_EmbedderConfig"), 0, nullptr); + DART_CHECK_VALID(embedder_config_type); + DART_CHECK_VALID( + Dart_SetField(embedder_config_type, ToDart("_mayExit"), Dart_False())); +} + +void RuntimeHolder::InitFuchsia() { + fidl::InterfaceHandle environment; + context_->ConnectToEnvironmentService(environment.NewRequest()); + fuchsia::dart::Initialize(std::move(environment), + std::move(outgoing_services_)); + + component::ServiceProviderPtr parent_env_service_provider; + context_->environment()->GetServices( + parent_env_service_provider.NewRequest()); + ConnectToService(parent_env_service_provider.get(), clipboard_.NewRequest()); +} + +void RuntimeHolder::InitZircon() { + Dart_Handle zircon_lib = Dart_LookupLibrary(ToDart("dart:zircon")); + DART_CHECK_VALID(zircon_lib); + + Dart_Handle namespace_type = + Dart_GetType(zircon_lib, ToDart("_Namespace"), 0, nullptr); + DART_CHECK_VALID(namespace_type); + DART_CHECK_VALID(Dart_SetField(namespace_type, ToDart("_namespace"), + ToDart(reinterpret_cast(namespc_)))); +} + +void RuntimeHolder::InitScenicInternal() { + fidl::InterfaceHandle view_container; + view_->GetContainer(view_container.NewRequest()); + + Dart_Handle mozart_internal = + Dart_LookupLibrary(ToDart("dart:mozart.internal")); + + DART_CHECK_VALID(Dart_SetNativeResolver(mozart_internal, mozart::NativeLookup, + mozart::NativeSymbol)); + + DART_CHECK_VALID( + Dart_SetField(mozart_internal, ToDart("_context"), + DartConverter::ToDart(reinterpret_cast( + static_cast(this))))); + + DART_CHECK_VALID(Dart_SetField(mozart_internal, ToDart("_viewContainer"), + ToDart(zircon::dart::Handle::Create( + view_container.TakeChannel().release())))); +} + +void RuntimeHolder::InitRootBundle(std::vector bundle) { + if (!bundle.empty()) { + root_bundle_data_ = std::move(bundle); + asset_store_ = fxl::MakeRefCounted( + GetUnzipperProviderForRootBundle()); + } else { + fxl::UniqueFD root_dir(fdio_ns_opendir(namespc_)); + if (!root_dir.is_valid()) { + FXL_LOG(ERROR) << "Unable to load root dir"; + return; + } + fxl::UniqueFD data_dir(openat(root_dir.get(), + kFuchsiaPackageResourceDirectory, + O_RDONLY | O_DIRECTORY)); + if (!data_dir.is_valid()) { + FXL_LOG(ERROR) << "Unable to load data dir"; + return; + } + asset_provider_ = + fxl::MakeRefCounted(std::move(data_dir)); + } +} + +views_v1::View* RuntimeHolder::GetMozartView() { + return view_.get(); +} + +bool RuntimeHolder::HandleAssetPlatformMessage( + blink::PlatformMessage* message) { + fxl::RefPtr response = message->response(); + if (!response) + return false; + const auto& data = message->data(); + std::string asset_name(reinterpret_cast(data.data()), + data.size()); + std::vector asset_data; + if (GetAssetAsBuffer(asset_name, &asset_data)) { + response->Complete(std::move(asset_data)); + } else { + response->CompleteEmpty(); + } + return true; +} + +bool RuntimeHolder::GetAssetAsBuffer(const std::string& name, + std::vector* data) { + return (asset_provider_ && + asset_provider_->GetAsBuffer(name, data)) || + (asset_store_ && asset_store_->GetAsBuffer(name, data)); +} + +bool RuntimeHolder::HandleFlutterPlatformMessage( + blink::PlatformMessage* message) { + const auto& data = message->data(); + rapidjson::Document document; + document.Parse(reinterpret_cast(data.data()), data.size()); + if (document.HasParseError() || !document.IsObject()) { + return false; + } + + auto root = document.GetObject(); + auto method = root.FindMember("method"); + if (method == root.MemberEnd() || !method->value.IsString()) { + return false; + } + + fxl::RefPtr response = message->response(); + if (method->value == "Clipboard.setData") { + auto text = root["args"]["text"].GetString(); + clipboard_->Push(text); + response->CompleteEmpty(); + } else if (method->value == "Clipboard.getData") { + clipboard_->Peek([response](fidl::StringPtr text) { + rapidjson::StringBuffer json_buffer; + rapidjson::Writer writer(json_buffer); + writer.StartArray(); + writer.StartObject(); + writer.Key("text"); + writer.String(text.get()); + writer.EndObject(); + writer.EndArray(); + + std::string result = json_buffer.GetString(); + response->Complete(std::vector{result.begin(), result.end()}); + }); + } else { + response->CompleteEmpty(); + } + return true; +} + +bool RuntimeHolder::HandleTextInputPlatformMessage( + blink::PlatformMessage* message) { + const auto& data = message->data(); + + rapidjson::Document document; + document.Parse(reinterpret_cast(data.data()), data.size()); + if (document.HasParseError() || !document.IsObject()) + return false; + auto root = document.GetObject(); + auto method = root.FindMember("method"); + if (method == root.MemberEnd() || !method->value.IsString()) + return false; + + if (method->value == "TextInput.show") { + if (input_method_editor_) { + input_method_editor_->Show(); + } + } else if (method->value == "TextInput.hide") { + if (input_method_editor_) { + input_method_editor_->Hide(); + } + } else if (method->value == "TextInput.setClient") { + current_text_input_client_ = 0; + if (text_input_binding_.is_bound()) + text_input_binding_.Unbind(); + input_method_editor_ = nullptr; + + auto args = root.FindMember("args"); + if (args == root.MemberEnd() || !args->value.IsArray() || + args->value.Size() != 2) + return false; + const auto& configuration = args->value[1]; + if (!configuration.IsObject()) + return false; + // TODO(abarth): Read the keyboard type form the configuration. + current_text_input_client_ = args->value[0].GetInt(); + input::TextInputState state; + state.text = std::string(); + input_connection_->GetInputMethodEditor( + input::KeyboardType::TEXT, input::InputMethodAction::DONE, + std::move(state), text_input_binding_.NewBinding(), + input_method_editor_.NewRequest()); + } else if (method->value == "TextInput.setEditingState") { + if (input_method_editor_) { + auto args_it = root.FindMember("args"); + if (args_it == root.MemberEnd() || !args_it->value.IsObject()) + return false; + const auto& args = args_it->value; + input::TextInputState state; + // TODO(abarth): Deserialize state. + auto text = args.FindMember("text"); + if (text != args.MemberEnd() && text->value.IsString()) + state.text = text->value.GetString(); + auto selection_base = args.FindMember("selectionBase"); + if (selection_base != args.MemberEnd() && selection_base->value.IsInt()) + state.selection.base = selection_base->value.GetInt(); + auto selection_extent = args.FindMember("selectionExtent"); + if (selection_extent != args.MemberEnd() && + selection_extent->value.IsInt()) + state.selection.extent = selection_extent->value.GetInt(); + auto selection_affinity = args.FindMember("selectionAffinity"); + if (selection_affinity != args.MemberEnd() && + selection_affinity->value.IsString() && + selection_affinity->value == "TextAffinity.upstream") + state.selection.affinity = input::TextAffinity::UPSTREAM; + else + state.selection.affinity = input::TextAffinity::DOWNSTREAM; + // We ignore selectionIsDirectional because that concept doesn't exist on + // Fuchsia. + auto composing_base = args.FindMember("composingBase"); + if (composing_base != args.MemberEnd() && composing_base->value.IsInt()) + state.composing.start = composing_base->value.GetInt(); + auto composing_extent = args.FindMember("composingExtent"); + if (composing_extent != args.MemberEnd() && + composing_extent->value.IsInt()) + state.composing.end = composing_extent->value.GetInt(); + input_method_editor_->SetState(std::move(state)); + } + } else if (method->value == "TextInput.clearClient") { + current_text_input_client_ = 0; + if (text_input_binding_.is_bound()) + text_input_binding_.Unbind(); + input_method_editor_ = nullptr; + } else { + FXL_DLOG(ERROR) << "Unknown " << kTextInputChannel << " method " + << method->value.GetString(); + } + + return false; +} + +blink::UnzipperProvider RuntimeHolder::GetUnzipperProviderForRootBundle() { + return [self = GetWeakPtr()]() { + if (!self) + return zip::UniqueUnzipper(); + return zip::CreateUnzipper(&self->root_bundle_data_); + }; +} + +void RuntimeHolder::OnEvent(input::InputEvent event, + OnEventCallback callback) { + bool handled = false; + if (event.is_pointer()) { + const input::PointerEvent& pointer = event.pointer(); + blink::PointerData pointer_data; + pointer_data.time_stamp = pointer.event_time / 1000; + pointer_data.change = GetChangeFromPointerEventPhase(pointer.phase); + pointer_data.kind = GetKindFromPointerType(pointer.type); + pointer_data.device = pointer.pointer_id; + pointer_data.physical_x = pointer.x * viewport_metrics_.device_pixel_ratio; + pointer_data.physical_y = pointer.y * viewport_metrics_.device_pixel_ratio; + // Buttons are single bit values starting with kMousePrimaryButton = 1. + pointer_data.buttons = static_cast(pointer.buttons); + + switch (pointer_data.change) { + case blink::PointerData::Change::kDown: + down_pointers_.insert(pointer_data.device); + break; + case blink::PointerData::Change::kCancel: + case blink::PointerData::Change::kUp: + down_pointers_.erase(pointer_data.device); + break; + case blink::PointerData::Change::kMove: + if (down_pointers_.count(pointer_data.device) == 0) + pointer_data.change = blink::PointerData::Change::kHover; + break; + case blink::PointerData::Change::kAdd: + if (down_pointers_.count(pointer_data.device) != 0) { + FXL_DLOG(ERROR) << "Received add event for down pointer."; + } + break; + case blink::PointerData::Change::kRemove: + if (down_pointers_.count(pointer_data.device) != 0) { + FXL_DLOG(ERROR) << "Received remove event for down pointer."; + } + break; + case blink::PointerData::Change::kHover: + if (down_pointers_.count(pointer_data.device) != 0) { + FXL_DLOG(ERROR) << "Received hover event for down pointer."; + } + break; + } + + blink::PointerDataPacket packet(1); + packet.SetPointerData(0, pointer_data); + runtime_->DispatchPointerDataPacket(packet); + + handled = true; + } else if (event.is_keyboard()) { + const input::KeyboardEvent& keyboard = event.keyboard(); + const char* type = nullptr; + if (keyboard.phase == input::KeyboardEventPhase::PRESSED) + type = "keydown"; + else if (keyboard.phase == input::KeyboardEventPhase::REPEAT) + type = "keydown"; // TODO change this to keyrepeat + else if (keyboard.phase == input::KeyboardEventPhase::RELEASED) + type = "keyup"; + + if (type) { + rapidjson::Document document; + auto& allocator = document.GetAllocator(); + document.SetObject(); + document.AddMember("type", rapidjson::Value(type, strlen(type)), + allocator); + document.AddMember("keymap", rapidjson::Value("fuchsia"), allocator); + document.AddMember("hidUsage", keyboard.hid_usage, allocator); + document.AddMember("codePoint", keyboard.code_point, allocator); + document.AddMember("modifiers", keyboard.modifiers, allocator); + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + + const uint8_t* data = + reinterpret_cast(buffer.GetString()); + runtime_->DispatchPlatformMessage( + fxl::MakeRefCounted( + kKeyEventChannel, + std::vector(data, data + buffer.GetSize()), nullptr)); + handled = true; + } + } + callback(handled); +} + +void RuntimeHolder::OnPropertiesChanged( + views_v1::ViewProperties properties, + OnPropertiesChangedCallback callback) { + // Attempt to read the device pixel ratio. + float pixel_ratio = 1.f; + if (auto& metrics = properties.display_metrics) { + pixel_ratio = metrics->device_pixel_ratio; + } + + // Apply view property changes. + if (auto& layout = properties.view_layout) { + viewport_metrics_.physical_width = layout->size.width * pixel_ratio; + viewport_metrics_.physical_height = layout->size.height * pixel_ratio; + viewport_metrics_.physical_padding_top = layout->inset.top * pixel_ratio; + viewport_metrics_.physical_padding_right = + layout->inset.right * pixel_ratio; + viewport_metrics_.physical_padding_bottom = + layout->inset.bottom * pixel_ratio; + viewport_metrics_.physical_padding_left = layout->inset.left * pixel_ratio; + viewport_metrics_.device_pixel_ratio = pixel_ratio; + runtime_->SetViewportMetrics(viewport_metrics_); + } + + ScheduleFrame(); + + callback(); +} + +void RuntimeHolder::DidUpdateState(input::TextInputState state, + input::InputEventPtr event) { + rapidjson::Document document; + auto& allocator = document.GetAllocator(); + + rapidjson::Value encoded_state(rapidjson::kObjectType); + encoded_state.AddMember("text", state.text.get(), allocator); + encoded_state.AddMember("selectionBase", state.selection.base, allocator); + encoded_state.AddMember("selectionExtent", state.selection.extent, + allocator); + switch (state.selection.affinity) { + case input::TextAffinity::UPSTREAM: + encoded_state.AddMember("selectionAffinity", + rapidjson::Value("TextAffinity.upstream"), + allocator); + break; + case input::TextAffinity::DOWNSTREAM: + encoded_state.AddMember("selectionAffinity", + rapidjson::Value("TextAffinity.downstream"), + allocator); + break; + } + encoded_state.AddMember("selectionIsDirectional", true, allocator); + encoded_state.AddMember("composingBase", state.composing.start, allocator); + encoded_state.AddMember("composingExtent", state.composing.end, allocator); + + rapidjson::Value args(rapidjson::kArrayType); + args.PushBack(current_text_input_client_, allocator); + args.PushBack(encoded_state, allocator); + + document.SetObject(); + document.AddMember("method", + rapidjson::Value("TextInputClient.updateEditingState"), + allocator); + document.AddMember("args", args, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + + const uint8_t* data = reinterpret_cast(buffer.GetString()); + runtime_->DispatchPlatformMessage(fxl::MakeRefCounted( + kTextInputChannel, std::vector(data, data + buffer.GetSize()), + nullptr)); +} + +void RuntimeHolder::OnAction(input::InputMethodAction action) { + rapidjson::Document document; + auto& allocator = document.GetAllocator(); + + rapidjson::Value args(rapidjson::kArrayType); + args.PushBack(current_text_input_client_, allocator); + + // Done is currently the only text input action defined by Flutter. + args.PushBack("TextInputAction.done", allocator); + + document.SetObject(); + document.AddMember( + "method", rapidjson::Value("TextInputClient.performAction"), allocator); + document.AddMember("args", args, allocator); + + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + document.Accept(writer); + + const uint8_t* data = reinterpret_cast(buffer.GetString()); + runtime_->DispatchPlatformMessage(fxl::MakeRefCounted( + kTextInputChannel, std::vector(data, data + buffer.GetSize()), + nullptr)); +} + +fxl::WeakPtr RuntimeHolder::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +void RuntimeHolder::PostBeginFrame() { + blink::Threads::Platform()->PostTask([weak_runtime_holder = GetWeakPtr()]() { + // On the Platform/UI thread. + ASSERT_IS_UI_THREAD; + if (weak_runtime_holder) { + weak_runtime_holder->BeginFrame(); + } + }); +} + +void RuntimeHolder::BeginFrame() { + ASSERT_IS_UI_THREAD + FXL_DCHECK(frame_scheduled_); + FXL_DCHECK(!frame_outstanding_); + frame_scheduled_ = false; + frame_outstanding_ = true; + int64_t dart_frame_start_micros = Dart_TimelineGetMicros(); + last_begin_frame_time_ = fxl::TimePoint::Now(); + runtime_->BeginFrame(last_begin_frame_time_); + + if (frame_scheduled_) { + // HACK(rmacnak): This assumes 16ms/frame; it should use the frame deadline + // once we have access to it. Compare shell/common/animator.cc. + runtime_->NotifyIdle(dart_frame_start_micros + 16000); + } else { + // We don't have another frame pending, so we're waiting on user input + // or I/O. Allow the Dart VM 100 ms. + runtime_->NotifyIdle(dart_frame_start_micros + 100000); + } +} + +void RuntimeHolder::OnFrameComplete() { + ASSERT_IS_UI_THREAD + FXL_DCHECK(frame_outstanding_); + frame_outstanding_ = false; + if (frame_scheduled_) + PostBeginFrame(); +} + +void RuntimeHolder::OnRedrawFrame() { + if (!frame_outstanding_) + ScheduleFrame(); +} + +} // namespace flutter_runner diff --git a/content_handler/runtime_holder.h b/content_handler/runtime_holder.h new file mode 100644 index 0000000000000..b9d55d9f9bacc --- /dev/null +++ b/content_handler/runtime_holder.h @@ -0,0 +1,152 @@ +// Copyright 2016 The Chromium 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_CONTENT_HANDLER_RUNTIME_HOLDER_H_ +#define FLUTTER_CONTENT_HANDLER_RUNTIME_HOLDER_H_ + +#include +#include + +#include + +#include "dart-pkg/fuchsia/sdk_ext/fuchsia.h" +#include "flutter/assets/asset_provider.h" +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/assets/unzipper_provider.h" +#include "flutter/assets/zip_asset_store.h" +#include "flutter/content_handler/accessibility_bridge.h" +#include "flutter/flow/layers/layer_tree.h" +#include "flutter/lib/ui/window/viewport_metrics.h" +#include "flutter/runtime/runtime_controller.h" +#include "flutter/runtime/runtime_delegate.h" +#include "lib/app/cpp/application_context.h" +#include +#include +#include +#include "lib/fidl/cpp/binding.h" +#include "lib/fxl/functional/closure.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" +#include "lib/ui/flutter/sdk_ext/src/natives.h" +#include +#include +#include + +namespace flutter_runner { + +class Rasterizer; + +class RuntimeHolder : public blink::RuntimeDelegate, + public mozart::NativesDelegate, + public views_v1::ViewListener, + public input::InputListener, + public input::InputMethodEditorClient { + public: + RuntimeHolder(); + ~RuntimeHolder(); + + void Init(fdio_ns_t* namespc, + std::unique_ptr context, + fidl::InterfaceRequest outgoing_services, + std::vector bundle); + void CreateView(const std::string& script_uri, + fidl::InterfaceRequest view_owner_request, + fidl::InterfaceRequest services); + + Dart_Port GetUIIsolateMainPort(); + std::string GetUIIsolateName(); + + int32_t return_code() { return return_code_; } + + void SetMainIsolateShutdownCallback(std::function callback); + + private: + // |blink::RuntimeDelegate| implementation: + std::string DefaultRouteName() override; + void ScheduleFrame(bool regenerate_layer_tree = true) override; + void Render(std::unique_ptr layer_tree) override; + void UpdateSemantics(blink::SemanticsNodeUpdates update) override; + void HandlePlatformMessage( + fxl::RefPtr message) override; + void DidCreateMainIsolate(Dart_Isolate isolate) override; + void DidShutdownMainIsolate() override; + + // |mozart::NativesDelegate| implementation: + views_v1::View* GetMozartView() override; + + // |input::InputListener| implementation: + void OnEvent(input::InputEvent event, + OnEventCallback callback) override; + + // |views_v1::ViewListener| implementation: + void OnPropertiesChanged( + views_v1::ViewProperties properties, + OnPropertiesChangedCallback callback) override; + + // |input::InputMethodEditorClient| implementation: + void DidUpdateState(input::TextInputState state, + input::InputEventPtr event) override; + void OnAction(input::InputMethodAction action) override; + + fxl::WeakPtr GetWeakPtr(); + + void InitRootBundle(std::vector bundle); + blink::UnzipperProvider GetUnzipperProviderForRootBundle(); + bool HandleAssetPlatformMessage(blink::PlatformMessage* message); + bool GetAssetAsBuffer(const std::string& name, std::vector* data); + bool HandleTextInputPlatformMessage(blink::PlatformMessage* message); + bool HandleFlutterPlatformMessage(blink::PlatformMessage* message); + + void InitDartIoInternal(); + void InitFuchsia(); + void InitZircon(); + void InitScenicInternal(); + + void PostBeginFrame(); + void BeginFrame(); + void OnFrameComplete(); + void OnRedrawFrame(); + void Invalidate(); + + fdio_ns_t* namespc_; + int dirfd_; + std::unique_ptr context_; + fidl::InterfaceRequest outgoing_services_; + std::vector root_bundle_data_; + // TODO(zarah): Remove asset_store_ when flx is completely removed + fxl::RefPtr asset_store_; + fxl::RefPtr asset_provider_; + void* dylib_handle_ = nullptr; + std::unique_ptr rasterizer_; + std::unique_ptr runtime_; + blink::ViewportMetrics viewport_metrics_; + views_v1::ViewManagerPtr view_manager_; + fidl::Binding view_listener_binding_; + fidl::Binding input_listener_binding_; + input::InputConnectionPtr input_connection_; + views_v1::ViewPtr view_; + std::unordered_set down_pointers_; + input::InputMethodEditorPtr input_method_editor_; + fidl::Binding text_input_binding_; + int current_text_input_client_ = 0; + fxl::TimePoint last_begin_frame_time_; + bool frame_outstanding_ = false; + bool frame_scheduled_ = false; + bool frame_rendering_ = false; + int32_t return_code_ = 0; + + fxl::WeakPtrFactory weak_factory_; + + std::unique_ptr accessibility_bridge_; + + std::function main_isolate_shutdown_callback_; + + modular::ClipboardPtr clipboard_; + + FXL_DISALLOW_COPY_AND_ASSIGN(RuntimeHolder); +}; + +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_RUNTIME_HOLDER_H_ diff --git a/content_handler/service_protocol_hooks.cc b/content_handler/service_protocol_hooks.cc new file mode 100644 index 0000000000000..9a91254f13488 --- /dev/null +++ b/content_handler/service_protocol_hooks.cc @@ -0,0 +1,164 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/content_handler/service_protocol_hooks.h" + +#include + +#include +#include + +#include "flutter/common/threads.h" +#include "flutter/content_handler/app.h" +#include "lib/fxl/memory/weak_ptr.h" + +namespace flutter_runner { +namespace { + +constexpr char kViewIdPrefx[] = "_flutterView/"; +constexpr size_t kViewIdPrefxLength = sizeof(kViewIdPrefx) - 1; + +static intptr_t KeyIndex(const char** param_keys, + intptr_t num_params, + const char* key) { + if (param_keys == NULL) { + return -1; + } + for (intptr_t i = 0; i < num_params; i++) { + if (strcmp(param_keys[i], key) == 0) { + return i; + } + } + return -1; +} + +static const char* ValueForKey(const char** param_keys, + const char** param_values, + intptr_t num_params, + const char* key) { + intptr_t index = KeyIndex(param_keys, num_params, key); + if (index < 0) { + return NULL; + } + return param_values[index]; +} + +static void AppendIsolateRef(std::stringstream* stream, + int64_t main_port, + const std::string name) { + *stream << "{\"type\":\"@Isolate\",\"fixedId\":true,\"id\":\"isolates/"; + *stream << main_port << "\",\"name\":\"" << name << "\","; + *stream << "\"number\":\"" << main_port << "\"}"; +} + +static void AppendFlutterView(std::stringstream* stream, + uintptr_t view_id, + int64_t isolate_id, + const std::string isolate_name) { + *stream << "{\"type\":\"FlutterView\", \"id\": \"" << kViewIdPrefx << "0x" + << std::hex << view_id << std::dec << "\""; + if (isolate_id != ILLEGAL_PORT) { + // Append the isolate (if it exists). + *stream << "," + << "\"isolate\":"; + AppendIsolateRef(stream, isolate_id, isolate_name); + } + *stream << "}"; +} + +} // namespace + +void ServiceProtocolHooks::RegisterHooks(bool running_precompiled_code) { + // Listing of FlutterViews. + Dart_RegisterRootServiceRequestCallback(kListViewsExtensionName, &ListViews, + nullptr); + + Dart_RegisterRootServiceRequestCallback(kSetAssetBundlePathExtensionName, + &SetAssetBundlePath, nullptr); +} + +const char* ServiceProtocolHooks::kListViewsExtensionName = + "_flutter.listViews"; + +bool ServiceProtocolHooks::ListViews(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + // Ask the App for the list of platform views. This will run a task on + // the UI thread before returning. + App& app = App::Shared(); + std::vector platform_views; + app.WaitForPlatformViewIds(&platform_views); + + std::stringstream response; + + response << "{\"type\":\"FlutterViewList\",\"views\":["; + bool prefix_comma = false; + for (auto it = platform_views.begin(); it != platform_views.end(); it++) { + uintptr_t view_id = it->view_id; + int64_t isolate_id = it->isolate_id; + const std::string& isolate_name = it->isolate_name; + if (!view_id) { + continue; + } + if (prefix_comma) { + response << ','; + } else { + prefix_comma = true; + } + AppendFlutterView(&response, view_id, isolate_id, isolate_name); + } + response << "]}"; + // Copy the response. + *json_object = strdup(response.str().c_str()); + return true; +} + +const char* ServiceProtocolHooks::kSetAssetBundlePathExtensionName = + "_flutter.setAssetBundlePath"; + +bool ServiceProtocolHooks::SetAssetBundlePath(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + const char* view_id_str = + ValueForKey(param_keys, param_values, num_params, "viewId"); + + // Ask the App for the list of platform views. This will run a task on + // the UI thread before returning. + App& app = App::Shared(); + std::vector platform_views; + app.WaitForPlatformViewIds(&platform_views); + + // Convert the actual flutter view hex id into a number. + uintptr_t view_id_as_num = + std::stoull((view_id_str + kViewIdPrefxLength), nullptr, 16); + + // The view existed and the isolate was created. Success. + std::stringstream response; + response << "{\"type\":\"Success\"," + << "\"view\":"; + for (auto it = platform_views.begin(); it != platform_views.end(); it++) { + uintptr_t view_id = it->view_id; + int64_t isolate_id = it->isolate_id; + const std::string& isolate_name = it->isolate_name; + if (!view_id || view_id != view_id_as_num) { + continue; + } + + // TODO(DX): Set up asset bundle path for the isolate. + + AppendFlutterView(&response, view_id, isolate_id, isolate_name); + break; + } + response << "}"; + *json_object = strdup(response.str().c_str()); + return true; +} + +} // namespace flutter_runner diff --git a/content_handler/service_protocol_hooks.h b/content_handler/service_protocol_hooks.h new file mode 100644 index 0000000000000..479fb71471f1e --- /dev/null +++ b/content_handler/service_protocol_hooks.h @@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium 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_CONTENT_HANDLER_SERVICE_PROTOCOL_HOOKS_H_ +#define FLUTTER_CONTENT_HANDLER_SERVICE_PROTOCOL_HOOKS_H_ + +#include "lib/fxl/synchronization/waitable_event.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +namespace flutter_runner { + +class ServiceProtocolHooks { + public: + static void RegisterHooks(bool running_precompiled_code); + + private: + static const char* kListViewsExtensionName; + static bool ListViews(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + + static const char* kSetAssetBundlePathExtensionName; + static bool SetAssetBundlePath(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); +}; + +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_SERVICE_PROTOCOL_HOOKS_H_ diff --git a/content_handler/session_connection.cc b/content_handler/session_connection.cc index 870020abb670f..b496ae37f40f2 100644 --- a/content_handler/session_connection.cc +++ b/content_handler/session_connection.cc @@ -2,69 +2,72 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "session_connection.h" - +#include "flutter/content_handler/session_connection.h" +#include "lib/fidl/cpp/optional.h" #include "lib/ui/scenic/fidl_helpers.h" -namespace flutter { +namespace flutter_runner { -SessionConnection::SessionConnection( - const ui::ScenicPtr& scenic, - std::string debug_label, - zx::eventpair import_token, - OnMetricsUpdate session_metrics_did_change_callback, - fxl::Closure session_error_callback) - : debug_label_(std::move(debug_label)), - session_(scenic.get()), +SessionConnection::SessionConnection(ui::ScenicPtr scenic, + zx::eventpair import_token) + : session_(scenic.get()), root_node_(&session_), surface_producer_(std::make_unique(&session_)), - scene_update_context_(&session_, surface_producer_.get()), - metrics_changed_callback_( - std::move(session_metrics_did_change_callback)) { - session_.set_error_handler(std::move(session_error_callback)); + scene_update_context_(&session_, surface_producer_.get()) { + ASSERT_IS_GPU_THREAD; + + session_.set_error_handler( + std::bind(&SessionConnection::OnSessionError, this)); session_.set_event_handler(std::bind(&SessionConnection::OnSessionEvents, this, std::placeholders::_1)); root_node_.Bind(std::move(import_token)); - root_node_.SetEventMask(ui::gfx::kMetricsEventMask); - session_.Present(0, [](ui::PresentationInfoPtr info) {}); -} + root_node_.SetEventMask(gfx::kMetricsEventMask); + session_.Present(0, [](images::PresentationInfo info) {}); -SessionConnection::~SessionConnection() = default; + present_callback_ = + std::bind(&SessionConnection::OnPresent, this, std::placeholders::_1); +} -void SessionConnection::OnSessionEvents(f1dl::Array events) { - using Type = ui::gfx::Event::Tag; +SessionConnection::~SessionConnection() { + ASSERT_IS_GPU_THREAD; +} - for (auto& raw_event : *events) { - if (!raw_event->is_gfx()) { - continue; - } +void SessionConnection::OnSessionError() { + ASSERT_IS_GPU_THREAD; + // TODO: Not this. + FXL_CHECK(false) << "Session connection was terminated."; +} - auto& event = raw_event->get_gfx(); - - switch (event->which()) { - case Type::METRICS: { - if (event->get_metrics()->node_id == root_node_.id()) { - auto& metrics = event->get_metrics()->metrics; - double device_pixel_ratio = metrics->scale_x; - scene_update_context_.set_metrics(std::move(metrics)); - if (metrics_changed_callback_) { - metrics_changed_callback_(device_pixel_ratio); - } - } - } break; - default: - break; +void SessionConnection::OnSessionEvents(fidl::VectorPtr events) { + gfx::Metrics* new_metrics; + for (auto& event : *events) { + if (event.is_gfx() && event.gfx().is_metrics() && + event.gfx().metrics().node_id == root_node_.id()) { + new_metrics = &event.gfx().metrics().metrics; } } + if (!new_metrics) + return; + + scene_update_context_.set_metrics(fidl::MakeOptional(std::move(*new_metrics))); + + if (metrics_changed_callback_) + metrics_changed_callback_(); } -void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame) { +void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame, + fxl::Closure on_present_callback) { + ASSERT_IS_GPU_THREAD; + FXL_DCHECK(pending_on_present_callback_ == nullptr); + FXL_DCHECK(on_present_callback != nullptr); + pending_on_present_callback_ = on_present_callback; + // Flush all session ops. Paint tasks have not yet executed but those are // fenced. The compositor can start processing ops while we finalize paint // tasks. - session_.Present(0, // presentation_time. (placeholder). - [](ui::PresentationInfoPtr) {} // callback + session_.Present(0, // presentation_time. Placeholder for now. + present_callback_ // callback ); // Execute paint tasks and signal fences. @@ -74,15 +77,22 @@ void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame) { // book-keeping on buffer caches. surface_producer_->OnSurfacesPresented(std::move(surfaces_to_submit)); - // Prepare for the next frame. These ops won't be processed till the next - // present. - EnqueueClearOps(); + // Prepare for the next frame. + EnqueueClearCommands(); +} + +void SessionConnection::OnPresent(images::PresentationInfo info) { + ASSERT_IS_GPU_THREAD; + auto callback = pending_on_present_callback_; + pending_on_present_callback_ = nullptr; + callback(); } -void SessionConnection::EnqueueClearOps() { +void SessionConnection::EnqueueClearCommands() { + ASSERT_IS_GPU_THREAD; // We are going to be sending down a fresh node hierarchy every frame. So just - // enqueue a detach op on the imported root node. + // enqueue a detach command on the imported root node. session_.Enqueue(scenic_lib::NewDetachChildrenCommand(root_node_.id())); } -} // namespace flutter +} // namespace flutter_runner diff --git a/content_handler/session_connection.h b/content_handler/session_connection.h index e4f39d314c98f..a80ba3a2235d2 100644 --- a/content_handler/session_connection.h +++ b/content_handler/session_connection.h @@ -2,62 +2,70 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#pragma once +#ifndef FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ +#define FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ #include +#include "flutter/common/threads.h" +#include "flutter/content_handler/vulkan_surface_producer.h" #include "flutter/flow/compositor_context.h" #include "flutter/flow/scene_update_context.h" -#include "lib/fidl/cpp/bindings/interface_handle.h" +#include "lib/fidl/cpp/interface_handle.h" #include "lib/fxl/functional/closure.h" #include "lib/fxl/macros.h" #include "lib/ui/scenic/client/resources.h" #include "lib/ui/scenic/client/session.h" -#include "vulkan_surface_producer.h" -namespace flutter { +namespace flutter_runner { -using OnMetricsUpdate = std::function; - -// The component residing on the GPU thread that is responsible for -// maintaining the Scenic session connection and presenting node updates. -class SessionConnection final { +class SessionConnection { public: - SessionConnection(const ui::ScenicPtr& scenic, - std::string debug_label, - zx::eventpair import_token, - OnMetricsUpdate session_metrics_did_change_callback, - fxl::Closure session_error_callback); + SessionConnection(ui::ScenicPtr scenic, zx::eventpair import_token); ~SessionConnection(); bool has_metrics() const { return scene_update_context_.has_metrics(); } - const ui::gfx::MetricsPtr& metrics() const { + const gfx::MetricsPtr& metrics() const { return scene_update_context_.metrics(); } + void set_metrics_changed_callback(fxl::Closure callback) { + metrics_changed_callback_ = std::move(callback); + } + flow::SceneUpdateContext& scene_update_context() { return scene_update_context_; } - scenic_lib::ImportNode& root_node() { return root_node_; } + scenic_lib::ImportNode& root_node() { + ASSERT_IS_GPU_THREAD; + return root_node_; + } - void Present(flow::CompositorContext::ScopedFrame& frame); + void Present(flow::CompositorContext::ScopedFrame& frame, + fxl::Closure on_present_callback); private: - const std::string debug_label_; scenic_lib::Session session_; scenic_lib::ImportNode root_node_; + scenic_lib::Session::PresentCallback present_callback_; + fxl::Closure pending_on_present_callback_; std::unique_ptr surface_producer_; flow::SceneUpdateContext scene_update_context_; - OnMetricsUpdate metrics_changed_callback_; + fxl::Closure metrics_changed_callback_; + + void OnSessionError(); + void OnSessionEvents(fidl::VectorPtr events); - void OnSessionEvents(f1dl::Array events); + void EnqueueClearCommands(); - void EnqueueClearOps(); + void OnPresent(images::PresentationInfo info); FXL_DISALLOW_COPY_AND_ASSIGN(SessionConnection); }; -} // namespace flutter +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ diff --git a/content_handler/surface.cc b/content_handler/surface.cc deleted file mode 100644 index 8efe1975fbfdb..0000000000000 --- a/content_handler/surface.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "surface.h" - -#include -#include -#include -#include - -#include "lib/fxl/files/unique_fd.h" - -namespace flutter { - -Surface::Surface(const ui::ScenicPtr& scenic, - std::string debug_label, - zx::eventpair import_token, - OnMetricsUpdate session_metrics_did_change_callback, - fxl::Closure session_error_callback) - : shell::Surface(std::make_unique( - scenic, - debug_label, - std::move(import_token), - std::move(session_metrics_did_change_callback), - std::move(session_error_callback))), - debug_label_(debug_label) {} - -Surface::~Surface() = default; - -// |shell::Surface| -bool Surface::IsValid() { - return valid_; -} - -// |shell::Surface| -std::unique_ptr Surface::AcquireFrame( - const SkISize& size) { - return std::make_unique( - nullptr, [](const shell::SurfaceFrame& surface_frame, SkCanvas* canvas) { - return true; - }); -} - -// |shell::Surface| -GrContext* Surface::GetContext() { - return nullptr; -} - -static zx_status_t DriverWatcher(int dirfd, - int event, - const char* fn, - void* cookie) { - if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) { - return ZX_ERR_STOP; - } - return ZX_OK; -} - -bool Surface::CanConnectToDisplay() { - constexpr char kDisplayDriverClass[] = "/dev/class/display"; - fxl::UniqueFD fd(open(kDisplayDriverClass, O_DIRECTORY | O_RDONLY)); - if (fd.get() < 0) { - FXL_DLOG(ERROR) << "Failed to open " << kDisplayDriverClass; - return false; - } - - zx_status_t status = fdio_watch_directory( - fd.get(), DriverWatcher, zx_deadline_after(ZX_SEC(1)), nullptr); - return status == ZX_ERR_STOP; -} - -} // namespace flutter diff --git a/content_handler/surface.h b/content_handler/surface.h deleted file mode 100644 index 4ad27aaf540f3..0000000000000 --- a/content_handler/surface.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include "compositor_context.h" -#include "flutter/fml/memory/weak_ptr.h" -#include "flutter/shell/common/surface.h" -#include "lib/fxl/macros.h" - -namespace flutter { - -// The interface between the Flutter rasterizer and the underlying platform. May -// be constructed on any thread but will be used by the engine only on the GPU -// thread. -class Surface final : public shell::Surface { - public: - Surface(const ui::ScenicPtr& scenic, - std::string debug_label, - zx::eventpair import_token, - OnMetricsUpdate session_metrics_did_change_callback, - fxl::Closure session_error_callback); - - ~Surface() override; - - private: - const bool valid_ = CanConnectToDisplay(); - const std::string debug_label_; - std::unique_ptr compositor_context_; - - // |shell::Surface| - bool IsValid() override; - - // |shell::Surface| - std::unique_ptr AcquireFrame( - const SkISize& size) override; - - // |shell::Surface| - GrContext* GetContext() override; - - static bool CanConnectToDisplay(); - - FXL_DISALLOW_COPY_AND_ASSIGN(Surface); -}; - -} // namespace flutter diff --git a/content_handler/task_observers.cc b/content_handler/task_observers.cc deleted file mode 100644 index f23265e7b1653..0000000000000 --- a/content_handler/task_observers.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "task_observers.h" - -#include - -#include "lib/fsl/tasks/message_loop.h" - -namespace flutter { - -thread_local std::map tTaskObservers; - -static void ExecuteAfterTaskObservers() { - for (const auto& callback : tTaskObservers) { - callback.second(); - } -} - -void CurrentMessageLoopAddAfterTaskObserver(intptr_t key, - fxl::Closure observer) { - if (!observer) { - return; - } - - if (tTaskObservers.size() == 0) { - fsl::MessageLoop::GetCurrent()->SetAfterTaskCallback( - std::bind(&ExecuteAfterTaskObservers)); - } - - tTaskObservers[key] = observer; -} - -void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key) { - tTaskObservers.erase(key); - - if (tTaskObservers.size() == 0) { - fsl::MessageLoop::GetCurrent()->ClearAfterTaskCallback(); - } -} - -} // namespace flutter diff --git a/content_handler/task_observers.h b/content_handler/task_observers.h deleted file mode 100644 index 53f6b96222000..0000000000000 --- a/content_handler/task_observers.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include "lib/fxl/functional/closure.h" - -namespace flutter { - -void CurrentMessageLoopAddAfterTaskObserver(intptr_t key, - fxl::Closure observer); - -void CurrentMessageLoopRemoveAfterTaskObserver(intptr_t key); - -} // namespace flutter diff --git a/content_handler/unique_fdio_ns.h b/content_handler/unique_fdio_ns.h deleted file mode 100644 index 726137d729f85..0000000000000 --- a/content_handler/unique_fdio_ns.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2018 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#pragma once - -#include "fdio/namespace.h" -#include "lib/fxl/logging.h" -#include "lib/fxl/memory/unique_object.h" - -namespace flutter { - -struct UniqueFDIONSTraits { - static fdio_ns_t* InvalidValue() { return nullptr; } - - static bool IsValid(fdio_ns_t* ns) { return ns != InvalidValue(); } - - static void Free(fdio_ns_t* ns) { - auto status = fdio_ns_destroy(ns); - FXL_DCHECK(status == ZX_OK); - } -}; - -using UniqueFDIONS = fxl::UniqueObject; - -inline UniqueFDIONS UniqueFDIONSCreate() { - fdio_ns_t* ns = nullptr; - if (fdio_ns_create(&ns) == ZX_OK) { - return UniqueFDIONS{ns}; - } - return UniqueFDIONS{nullptr}; -} - -} // namespace flutter diff --git a/content_handler/vulkan_rasterizer.cc b/content_handler/vulkan_rasterizer.cc new file mode 100644 index 0000000000000..25f90c460ce3f --- /dev/null +++ b/content_handler/vulkan_rasterizer.cc @@ -0,0 +1,117 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/content_handler/vulkan_rasterizer.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "flutter/common/threads.h" +#include "flutter/glue/trace_event.h" +#include "lib/fxl/files/unique_fd.h" + +namespace flutter_runner { + +constexpr char kGpuDriverClass[] = "/dev/class/gpu"; + +static zx_status_t DriverWatcher(int dirfd, + int event, + const char* fn, + void* cookie) { + if (event == WATCH_EVENT_ADD_FILE && !strcmp(fn, "000")) { + return ZX_ERR_STOP; + } + return ZX_OK; +} + +bool WaitForFirstGpuDriver() { + fxl::UniqueFD fd(open(kGpuDriverClass, O_DIRECTORY | O_RDONLY)); + if (fd.get() < 0) { + FXL_DLOG(ERROR) << "Failed to open " << kGpuDriverClass; + return false; + } + + zx_status_t status = fdio_watch_directory( + fd.get(), DriverWatcher, zx_deadline_after(ZX_SEC(5)), nullptr); + return status == ZX_ERR_STOP; +} + +VulkanRasterizer::VulkanRasterizer() : compositor_context_(nullptr) { + valid_ = WaitForFirstGpuDriver(); +} + +VulkanRasterizer::~VulkanRasterizer() = default; + +bool VulkanRasterizer::IsValid() const { + return valid_; +} + +void VulkanRasterizer::SetScene(fidl::InterfaceHandle scenic, + zx::eventpair import_token, + fxl::Closure metrics_changed_callback) { + ASSERT_IS_GPU_THREAD; + FXL_DCHECK(valid_ && !session_connection_); + session_connection_ = std::make_unique( + scenic.Bind(), std::move(import_token)); + session_connection_->set_metrics_changed_callback( + std::move(metrics_changed_callback)); +} + +void VulkanRasterizer::Draw(std::unique_ptr layer_tree, + fxl::Closure callback) { + ASSERT_IS_GPU_THREAD; + FXL_DCHECK(callback != nullptr); + + if (layer_tree == nullptr) { + FXL_LOG(ERROR) << "Layer tree was not valid."; + callback(); + return; + } + + if (!session_connection_) { + FXL_LOG(ERROR) << "Session was not valid."; + callback(); + return; + } + + if (!session_connection_->has_metrics()) { + // Still awaiting metrics. Will redraw when we get them. + callback(); + return; + } + + compositor_context_.engine_time().SetLapTime(layer_tree->construction_time()); + + flow::CompositorContext::ScopedFrame frame = compositor_context_.AcquireFrame( + nullptr, nullptr, true /* instrumentation enabled */); + { + // Preroll the Flutter layer tree. This allows Flutter to perform pre-paint + // optimizations. + TRACE_EVENT0("flutter", "Preroll"); + layer_tree->Preroll(frame, session_connection_->metrics().get()); + } + + { + // Traverse the Flutter layer tree so that the necessary session ops to + // represent the frame are enqueued in the underlying session. + TRACE_EVENT0("flutter", "UpdateScene"); + layer_tree->UpdateScene(session_connection_->scene_update_context(), + session_connection_->root_node()); + } + + { + // Flush all pending session ops. + TRACE_EVENT0("flutter", "SessionPresent"); + session_connection_->Present( + frame, [callback = std::move(callback)]() { callback(); }); + } +} + +} // namespace flutter_runner diff --git a/content_handler/vulkan_rasterizer.h b/content_handler/vulkan_rasterizer.h new file mode 100644 index 0000000000000..c3ae211553f5a --- /dev/null +++ b/content_handler/vulkan_rasterizer.h @@ -0,0 +1,42 @@ +// Copyright 2017 The Chromium 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_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ +#define FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ + +#include + +#include "flutter/content_handler/rasterizer.h" +#include "flutter/content_handler/session_connection.h" +#include "flutter/flow/compositor_context.h" +#include "lib/fxl/macros.h" + +namespace flutter_runner { + +class VulkanRasterizer : public Rasterizer { + public: + VulkanRasterizer(); + + ~VulkanRasterizer() override; + + bool IsValid() const; + + void SetScene(fidl::InterfaceHandle scenic, + zx::eventpair import_token, + fxl::Closure metrics_changed_callback) override; + + void Draw(std::unique_ptr layer_tree, + fxl::Closure callback) override; + + private: + flow::CompositorContext compositor_context_; + std::unique_ptr session_connection_; + bool valid_; + + FXL_DISALLOW_COPY_AND_ASSIGN(VulkanRasterizer); +}; + +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_VULKAN_RASTERIZER_H_ diff --git a/content_handler/vulkan_surface.cc b/content_handler/vulkan_surface.cc index c78ad6c127545..47ac87e375e81 100644 --- a/content_handler/vulkan_surface.cc +++ b/content_handler/vulkan_surface.cc @@ -2,16 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "vulkan_surface.h" - #include +#include "flutter/content_handler/vulkan_surface.h" +#include "flutter/common/threads.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" #include "third_party/skia/include/gpu/GrContext.h" -namespace flutter { +namespace flutter_runner { VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider, sk_sp context, @@ -22,6 +22,8 @@ VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider, backend_context_(std::move(backend_context)), session_(session), wait_(this) { + ASSERT_IS_GPU_THREAD; + FXL_DCHECK(session_); zx::vmo exported_vmo; @@ -53,6 +55,7 @@ VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider, } VulkanSurface::~VulkanSurface() { + ASSERT_IS_GPU_THREAD; if (async_) { wait_.Cancel(async_); wait_.set_object(ZX_HANDLE_INVALID); @@ -322,6 +325,7 @@ bool VulkanSurface::PushSessionImageSetupOps(scenic_lib::Session* session, } scenic_lib::Image* VulkanSurface::GetImage() { + ASSERT_IS_GPU_THREAD; if (!valid_) { return 0; } @@ -329,6 +333,7 @@ scenic_lib::Image* VulkanSurface::GetImage() { } sk_sp VulkanSurface::GetSkiaSurface() const { + ASSERT_IS_GPU_THREAD; return valid_ ? sk_surface_ : nullptr; } @@ -353,6 +358,7 @@ bool VulkanSurface::FlushSessionAcquireAndReleaseEvents() { void VulkanSurface::SignalWritesFinished( std::function on_writes_committed) { + ASSERT_IS_GPU_THREAD; FXL_DCHECK(on_writes_committed); if (!valid_) { @@ -368,6 +374,8 @@ void VulkanSurface::SignalWritesFinished( } void VulkanSurface::Reset() { + ASSERT_IS_GPU_THREAD; + if (acquire_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK || release_event_.signal(ZX_EVENT_SIGNALED, 0u) != ZX_OK) { valid_ = false; @@ -402,10 +410,10 @@ void VulkanSurface::Reset() { } } -async_wait_result_t VulkanSurface::OnHandleReady( - async_t* async, - zx_status_t status, - const zx_packet_signal_t* signal) { +async_wait_result_t VulkanSurface::OnHandleReady(async_t* async, + zx_status_t status, + const zx_packet_signal_t* signal) { + ASSERT_IS_GPU_THREAD; if (status != ZX_OK) return ASYNC_WAIT_FINISHED; FXL_DCHECK(signal->observed & ZX_EVENT_SIGNALED); @@ -413,4 +421,4 @@ async_wait_result_t VulkanSurface::OnHandleReady( return ASYNC_WAIT_AGAIN; } -} // namespace flutter +} // namespace flutter_runner diff --git a/content_handler/vulkan_surface.h b/content_handler/vulkan_surface.h index 7add6b05bb8cc..41a807af81f9c 100644 --- a/content_handler/vulkan_surface.h +++ b/content_handler/vulkan_surface.h @@ -20,10 +20,9 @@ #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" -namespace flutter { +namespace flutter_runner { -class VulkanSurface final - : public flow::SceneUpdateContext::SurfaceProducerSurface { +class VulkanSurface : public flow::SceneUpdateContext::SurfaceProducerSurface { public: VulkanSurface(vulkan::VulkanProvider& vulkan_provider, sk_sp context, @@ -33,16 +32,12 @@ class VulkanSurface final ~VulkanSurface() override; - // |flow::SceneUpdateContext::SurfaceProducerSurface| size_t AdvanceAndGetAge() override; - // |flow::SceneUpdateContext::SurfaceProducerSurface| bool FlushSessionAcquireAndReleaseEvents() override; - // |flow::SceneUpdateContext::SurfaceProducerSurface| bool IsValid() const override; - // |flow::SceneUpdateContext::SurfaceProducerSurface| SkISize GetSize() const override; // Note: It is safe for the caller to collect the surface in the @@ -120,4 +115,4 @@ class VulkanSurface final FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurface); }; -} // namespace flutter +} // namespace flutter_runner diff --git a/content_handler/vulkan_surface_pool.cc b/content_handler/vulkan_surface_pool.cc index 93d14c2ddbff7..af23ef711b7ad 100644 --- a/content_handler/vulkan_surface_pool.cc +++ b/content_handler/vulkan_surface_pool.cc @@ -2,14 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "vulkan_surface_pool.h" - #include +#include "flutter/content_handler/vulkan_surface_pool.h" #include "flutter/glue/trace_event.h" #include "third_party/skia/include/gpu/GrContext.h" -namespace flutter { +namespace flutter_runner { VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProvider& vulkan_provider, sk_sp context, @@ -178,4 +177,4 @@ void VulkanSurfacePool::TraceStats() { trace_surfaces_reused_ = 0; } -} // namespace flutter +} // namespace flutter_runner diff --git a/content_handler/vulkan_surface_pool.h b/content_handler/vulkan_surface_pool.h index 4900816762910..52dd3ed6aa417 100644 --- a/content_handler/vulkan_surface_pool.h +++ b/content_handler/vulkan_surface_pool.h @@ -6,13 +6,12 @@ #include #include - +#include "flutter/content_handler/vulkan_surface.h" #include "lib/fxl/macros.h" -#include "vulkan_surface.h" -namespace flutter { +namespace flutter_runner { -class VulkanSurfacePool final { +class VulkanSurfacePool { public: static const size_t kMaxSurfacesOfSameSize = 3; static const size_t kMaxSurfaceAge = 3; @@ -75,4 +74,4 @@ class VulkanSurfacePool final { FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfacePool); }; -} // namespace flutter +} // namespace flutter_runner diff --git a/content_handler/vulkan_surface_producer.cc b/content_handler/vulkan_surface_producer.cc index ff8a9ab9d1f4a..6f605c109b7df 100644 --- a/content_handler/vulkan_surface_producer.cc +++ b/content_handler/vulkan_surface_producer.cc @@ -2,18 +2,17 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "vulkan_surface_producer.h" +#include "flutter/content_handler/vulkan_surface_producer.h" #include #include #include - #include "flutter/glue/trace_event.h" #include "third_party/skia/include/gpu/GrBackendSemaphore.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/skia/include/gpu/vk/GrVkTypes.h" -namespace flutter { +namespace flutter_runner { VulkanSurfaceProducer::VulkanSurfaceProducer( scenic_lib::Session* mozart_session) { @@ -43,7 +42,7 @@ bool VulkanSurfaceProducer::Initialize(scenic_lib::Session* mozart_session) { VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, }; application_ = std::make_unique( - *vk_, "FlutterApplicationRunner", std::move(extensions)); + *vk_, "FlutterContentHandler", std::move(extensions)); if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) { // Make certain the application instance was created and it setup the @@ -201,4 +200,4 @@ void VulkanSurfaceProducer::SubmitSurface( surface_pool_->SubmitSurface(std::move(surface)); } -} // namespace flutter +} // namespace flutter_runner diff --git a/content_handler/vulkan_surface_producer.h b/content_handler/vulkan_surface_producer.h index 15c4419e8cde7..2338a8a6ba709 100644 --- a/content_handler/vulkan_surface_producer.h +++ b/content_handler/vulkan_surface_producer.h @@ -2,8 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#pragma once +#ifndef FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ +#define FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ +#include "flutter/content_handler/vulkan_surface.h" +#include "flutter/content_handler/vulkan_surface_pool.h" #include "flutter/flow/scene_update_context.h" #include "flutter/vulkan/vulkan_application.h" #include "flutter/vulkan/vulkan_device.h" @@ -14,14 +17,11 @@ #include "lib/ui/scenic/client/resources.h" #include "lib/ui/scenic/client/session.h" #include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" -#include "vulkan_surface.h" -#include "vulkan_surface_pool.h" -namespace flutter { +namespace flutter_runner { -class VulkanSurfaceProducer final - : public flow::SceneUpdateContext::SurfaceProducer, - public vulkan::VulkanProvider { +class VulkanSurfaceProducer : public flow::SceneUpdateContext::SurfaceProducer, + public vulkan::VulkanProvider { public: VulkanSurfaceProducer(scenic_lib::Session* mozart_session); @@ -74,4 +74,6 @@ class VulkanSurfaceProducer final FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfaceProducer); }; -} // namespace flutter +} // namespace flutter_runner + +#endif // FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ diff --git a/flow/BUILD.gn b/flow/BUILD.gn index 07c5d4e5d4e7b..e6a6411a6c1da 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -48,12 +48,11 @@ source_set("flow") { "matrix_decomposition.h", "paint_utils.cc", "paint_utils.h", + "process_info.h", "raster_cache.cc", "raster_cache.h", "raster_cache_key.cc", "raster_cache_key.h", - "skia_gpu_object.cc", - "skia_gpu_object.h", "texture.cc", "texture.h", ] @@ -62,11 +61,12 @@ source_set("flow") { "//garnet/public/lib/fxl", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] deps = [ "$flutter_root/common", - "$flutter_root/fml", "$flutter_root/glue", "$flutter_root/synchronization", "//third_party/skia", @@ -103,8 +103,8 @@ executable("flow_unittests") { deps = [ ":flow", - "$flutter_root/testing", "//third_party/dart/runtime:libdart_jit", # for tracing + "$flutter_root/testing", "//third_party/skia", ] } diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index 53659103be9f1..e0d17229e7981 100644 --- a/flow/compositor_context.cc +++ b/flow/compositor_context.cc @@ -4,12 +4,12 @@ #include "flutter/flow/compositor_context.h" -#include "flutter/flow/layers/layer_tree.h" #include "third_party/skia/include/core/SkCanvas.h" namespace flow { -CompositorContext::CompositorContext() = default; +CompositorContext::CompositorContext(std::unique_ptr info) + : process_info_(std::move(info)) {} CompositorContext::~CompositorContext() = default; @@ -18,6 +18,10 @@ void CompositorContext::BeginFrame(ScopedFrame& frame, if (enable_instrumentation) { frame_count_.Increment(); frame_time_.Start(); + + if (process_info_ && process_info_->SampleNow()) { + memory_usage_.Add(process_info_->GetResidentMemorySize()); + } } } @@ -29,12 +33,11 @@ void CompositorContext::EndFrame(ScopedFrame& frame, } } -std::unique_ptr CompositorContext::AcquireFrame( +CompositorContext::ScopedFrame CompositorContext::AcquireFrame( GrContext* gr_context, SkCanvas* canvas, bool instrumentation_enabled) { - return std::make_unique(*this, gr_context, canvas, - instrumentation_enabled); + return ScopedFrame(*this, gr_context, canvas, instrumentation_enabled); } CompositorContext::ScopedFrame::ScopedFrame(CompositorContext& context, @@ -48,23 +51,18 @@ CompositorContext::ScopedFrame::ScopedFrame(CompositorContext& context, context_.BeginFrame(*this, instrumentation_enabled_); } +CompositorContext::ScopedFrame::ScopedFrame(ScopedFrame&& frame) = default; + CompositorContext::ScopedFrame::~ScopedFrame() { context_.EndFrame(*this, instrumentation_enabled_); } -bool CompositorContext::ScopedFrame::Raster(flow::LayerTree& layer_tree, - bool ignore_raster_cache) { - layer_tree.Preroll(*this, ignore_raster_cache); - layer_tree.Paint(*this); - return true; -} - void CompositorContext::OnGrContextCreated() { - texture_registry_.OnGrContextCreated(); + texture_registry_->OnGrContextCreated(); } void CompositorContext::OnGrContextDestroyed() { - texture_registry_.OnGrContextDestroyed(); + texture_registry_->OnGrContextDestroyed(); raster_cache_.Clear(); } diff --git a/flow/compositor_context.h b/flow/compositor_context.h index 14c2449dbecd0..2d310422747b7 100644 --- a/flow/compositor_context.h +++ b/flow/compositor_context.h @@ -9,6 +9,7 @@ #include #include "flutter/flow/instrumentation.h" +#include "flutter/flow/process_info.h" #include "flutter/flow/raster_cache.h" #include "flutter/flow/texture.h" #include "lib/fxl/macros.h" @@ -17,26 +18,19 @@ namespace flow { -class LayerTree; - class CompositorContext { public: class ScopedFrame { public: - ScopedFrame(CompositorContext& context, - GrContext* gr_context, - SkCanvas* canvas, - bool instrumentation_enabled); - - virtual ~ScopedFrame(); - SkCanvas* canvas() { return canvas_; } CompositorContext& context() const { return context_; } GrContext* gr_context() const { return gr_context_; } - virtual bool Raster(LayerTree& layer_tree, bool ignore_raster_cache); + ScopedFrame(ScopedFrame&& frame); + + ~ScopedFrame(); private: CompositorContext& context_; @@ -44,17 +38,23 @@ class CompositorContext { SkCanvas* canvas_; const bool instrumentation_enabled_; + ScopedFrame(CompositorContext& context, + GrContext* gr_context, + SkCanvas* canvas, + bool instrumentation_enabled); + + friend class CompositorContext; + FXL_DISALLOW_COPY_AND_ASSIGN(ScopedFrame); }; - CompositorContext(); + CompositorContext(std::unique_ptr info); - virtual ~CompositorContext(); + ~CompositorContext(); - virtual std::unique_ptr AcquireFrame( - GrContext* gr_context, - SkCanvas* canvas, - bool instrumentation_enabled); + ScopedFrame AcquireFrame(GrContext* gr_context, + SkCanvas* canvas, + bool instrumentation_enabled = true); void OnGrContextCreated(); @@ -62,7 +62,7 @@ class CompositorContext { RasterCache& raster_cache() { return raster_cache_; } - TextureRegistry& texture_registry() { return texture_registry_; } + TextureRegistry& texture_registry() { return *texture_registry_; } const Counter& frame_count() const { return frame_count_; } @@ -70,12 +70,20 @@ class CompositorContext { Stopwatch& engine_time() { return engine_time_; } + const CounterValues& memory_usage() const { return memory_usage_; } + + void SetTextureRegistry(TextureRegistry* textureRegistry) { + texture_registry_ = textureRegistry; + } + private: RasterCache raster_cache_; - TextureRegistry texture_registry_; + TextureRegistry* texture_registry_; + std::unique_ptr process_info_; Counter frame_count_; Stopwatch frame_time_; Stopwatch engine_time_; + CounterValues memory_usage_; void BeginFrame(ScopedFrame& frame, bool enable_instrumentation); diff --git a/flow/debug_print.cc b/flow/debug_print.cc index 3311b9c2b43e3..0aa5b4b3b7d2d 100644 --- a/flow/debug_print.cc +++ b/flow/debug_print.cc @@ -80,8 +80,3 @@ std::ostream& operator<<(std::ostream& os, const flow::RasterCacheKey& k) { ; return os; } - -std::ostream& operator<<(std::ostream& os, const SkISize& size) { - os << size.width() << ", " << size.height(); - return os; -} diff --git a/flow/debug_print.h b/flow/debug_print.h index 78a28fe38562d..ca5973eeb0977 100644 --- a/flow/debug_print.h +++ b/flow/debug_print.h @@ -15,15 +15,14 @@ #define DEF_PRINTER(x) std::ostream& operator<<(std::ostream&, const x&); -DEF_PRINTER(flow::MatrixDecomposition); DEF_PRINTER(flow::RasterCacheKey); -DEF_PRINTER(SkISize); +DEF_PRINTER(flow::MatrixDecomposition); DEF_PRINTER(SkMatrix); DEF_PRINTER(SkMatrix44); -DEF_PRINTER(SkPoint); -DEF_PRINTER(SkRect); -DEF_PRINTER(SkRRect); DEF_PRINTER(SkVector3); DEF_PRINTER(SkVector4); +DEF_PRINTER(SkRect); +DEF_PRINTER(SkRRect); +DEF_PRINTER(SkPoint); #endif // FLUTTER_FLOW_DEBUG_PRINT_H_ diff --git a/flow/export_node.cc b/flow/export_node.cc index 27ab34030ca42..a130c426a75bf 100644 --- a/flow/export_node.cc +++ b/flow/export_node.cc @@ -4,27 +4,28 @@ #include "flutter/flow/export_node.h" +#include "flutter/common/threads.h" #include "lib/fxl/functional/make_copyable.h" namespace flow { ExportNodeHolder::ExportNodeHolder( - fxl::RefPtr gpu_task_runner, fxl::RefPtr export_token_handle) - : gpu_task_runner_(std::move(gpu_task_runner)), - export_node_(std::make_unique(export_token_handle)) { - FXL_DCHECK(gpu_task_runner_); + : export_node_(std::make_unique(export_token_handle)) { + ASSERT_IS_UI_THREAD; } void ExportNodeHolder::Bind(SceneUpdateContext& context, scenic_lib::ContainerNode& container, const SkPoint& offset, bool hit_testable) { + ASSERT_IS_GPU_THREAD; export_node_->Bind(context, container, offset, hit_testable); } ExportNodeHolder::~ExportNodeHolder() { - gpu_task_runner_->PostTask( + ASSERT_IS_UI_THREAD; + blink::Threads::Gpu()->PostTask( fxl::MakeCopyable([export_node = std::move(export_node_)]() { export_node->Dispose(true); })); @@ -43,6 +44,8 @@ void ExportNode::Bind(SceneUpdateContext& context, scenic_lib::ContainerNode& container, const SkPoint& offset, bool hit_testable) { + ASSERT_IS_GPU_THREAD; + if (export_token_) { // Happens first time we bind. node_.reset(new scenic_lib::EntityNode(container.session())); @@ -64,6 +67,8 @@ void ExportNode::Bind(SceneUpdateContext& context, } void ExportNode::Dispose(bool remove_from_scene_update_context) { + ASSERT_IS_GPU_THREAD; + // If scene_update_context_ is set, then we should still have a node left to // dereference. // If scene_update_context_ is null, then either: diff --git a/flow/export_node.h b/flow/export_node.h index e6a11175e561e..24f94fcebf20f 100644 --- a/flow/export_node.h +++ b/flow/export_node.h @@ -15,7 +15,6 @@ #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_counted.h" #include "lib/ui/scenic/client/resources.h" -#include "third_party/flutter/fml/task_runner.h" #include "third_party/skia/include/core/SkPoint.h" namespace flow { @@ -25,8 +24,7 @@ namespace flow { // held by the ExportNode. class ExportNodeHolder : public fxl::RefCountedThreadSafe { public: - ExportNodeHolder(fxl::RefPtr gpu_task_runner, - fxl::RefPtr export_token_handle); + ExportNodeHolder(fxl::RefPtr export_token_handle); ~ExportNodeHolder(); // Calls Bind() on the wrapped ExportNode. @@ -38,7 +36,6 @@ class ExportNodeHolder : public fxl::RefCountedThreadSafe { ExportNode* export_node() { return export_node_.get(); } private: - fxl::RefPtr gpu_task_runner_; std::unique_ptr export_node_; FRIEND_MAKE_REF_COUNTED(ExportNodeHolder); diff --git a/flow/layers/default_layer_builder.cc b/flow/layers/default_layer_builder.cc index ca228a7d58f76..a33b0eaa681b7 100644 --- a/flow/layers/default_layer_builder.cc +++ b/flow/layers/default_layer_builder.cc @@ -137,20 +137,20 @@ void DefaultLayerBuilder::PushPerformanceOverlay(uint64_t enabled_options, } void DefaultLayerBuilder::PushPicture(const SkPoint& offset, - SkiaGPUObject picture, + sk_sp picture, bool picture_is_complex, bool picture_will_change) { if (!current_layer_) { return; } - SkRect pictureRect = picture.get()->cullRect(); + SkRect pictureRect = picture->cullRect(); pictureRect.offset(offset.x(), offset.y()); if (!SkRect::Intersects(pictureRect, cull_rects_.top())) { return; } auto layer = std::make_unique(); layer->set_offset(offset); - layer->set_picture(std::move(picture)); + layer->set_picture(picture); layer->set_is_complex(picture_is_complex); layer->set_will_change(picture_will_change); current_layer_->Add(std::move(layer)); diff --git a/flow/layers/default_layer_builder.h b/flow/layers/default_layer_builder.h index cadd173ab5a84..a62ec46714d21 100644 --- a/flow/layers/default_layer_builder.h +++ b/flow/layers/default_layer_builder.h @@ -59,7 +59,7 @@ class DefaultLayerBuilder final : public LayerBuilder { // |flow::LayerBuilder| void PushPicture(const SkPoint& offset, - SkiaGPUObject picture, + sk_sp picture, bool picture_is_complex, bool picture_will_change) override; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index cf7ad71c36fae..d0ef1990ab4f2 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -44,6 +44,9 @@ class Layer { virtual ~Layer(); struct PrerollContext { +#if defined(OS_FUCHSIA) + gfx::Metrics* metrics = nullptr; +#endif RasterCache* raster_cache; GrContext* gr_context; SkColorSpace* dst_color_space; @@ -56,6 +59,7 @@ class Layer { SkCanvas& canvas; const Stopwatch& frame_time; const Stopwatch& engine_time; + const CounterValues& memory_usage; TextureRegistry& texture_registry; const bool checkerboard_offscreen_layers; }; diff --git a/flow/layers/layer_builder.h b/flow/layers/layer_builder.h index a29e959514428..91ae13974a23b 100644 --- a/flow/layers/layer_builder.h +++ b/flow/layers/layer_builder.h @@ -8,7 +8,6 @@ #include #include "flutter/flow/layers/layer.h" -#include "flutter/flow/skia_gpu_object.h" #include "garnet/public/lib/fxl/macros.h" #include "third_party/skia/include/core/SkBlendMode.h" #include "third_party/skia/include/core/SkColor.h" @@ -58,7 +57,7 @@ class LayerBuilder { const SkRect& rect) = 0; virtual void PushPicture(const SkPoint& offset, - SkiaGPUObject picture, + sk_sp picture, bool picture_is_complex, bool picture_will_change) = 0; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index d9fb374194688..fde2fc4bf0866 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -17,18 +17,43 @@ LayerTree::LayerTree() LayerTree::~LayerTree() = default; +void LayerTree::Raster(CompositorContext::ScopedFrame& frame, +#if defined(OS_FUCHSIA) + gfx::Metrics* metrics, +#endif + bool ignore_raster_cache) { +#if defined(OS_FUCHSIA) + FXL_DCHECK(metrics); +#endif + Preroll(frame, +#if defined(OS_FUCHSIA) + metrics, +#endif + ignore_raster_cache); + Paint(frame); +} + void LayerTree::Preroll(CompositorContext::ScopedFrame& frame, +#if defined(OS_FUCHSIA) + gfx::Metrics* metrics, +#endif bool ignore_raster_cache) { +#if defined(OS_FUCHSIA) + FXL_DCHECK(metrics); +#endif TRACE_EVENT0("flutter", "LayerTree::Preroll"); SkColorSpace* color_space = frame.canvas() ? frame.canvas()->imageInfo().colorSpace() : nullptr; frame.context().raster_cache().SetCheckboardCacheImages( checkerboard_raster_cache_images_); Layer::PrerollContext context = { - ignore_raster_cache ? nullptr : &frame.context().raster_cache(), - frame.gr_context(), - color_space, - SkRect::MakeEmpty(), +#if defined(OS_FUCHSIA) + metrics, +#endif + ignore_raster_cache ? nullptr : &frame.context().raster_cache(), + frame.gr_context(), + color_space, + SkRect::MakeEmpty(), }; root_layer_->Preroll(&context, SkMatrix::I()); @@ -38,12 +63,9 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame, void LayerTree::UpdateScene(SceneUpdateContext& context, scenic_lib::ContainerNode& container) { TRACE_EVENT0("flutter", "LayerTree::UpdateScene"); - const auto& metrics = context.metrics(); - SceneUpdateContext::Transform transform(context, // context - 1.0f / metrics->scale_x, // X - 1.0f / metrics->scale_y, // Y - 1.0f / metrics->scale_z // Z - ); + + SceneUpdateContext::Transform transform(context, 1.f / device_pixel_ratio_, + 1.f / device_pixel_ratio_, 1.f); SceneUpdateContext::Frame frame( context, SkRRect::MakeRect( @@ -60,13 +82,12 @@ void LayerTree::UpdateScene(SceneUpdateContext& context, #endif void LayerTree::Paint(CompositorContext::ScopedFrame& frame) const { - Layer::PaintContext context = { - *frame.canvas(), // - frame.context().frame_time(), // - frame.context().engine_time(), // - frame.context().texture_registry(), // - checkerboard_offscreen_layers_ // - }; + Layer::PaintContext context = {*frame.canvas(), + frame.context().frame_time(), + frame.context().engine_time(), + frame.context().memory_usage(), + frame.context().texture_registry(), + checkerboard_offscreen_layers_}; TRACE_EVENT0("flutter", "LayerTree::Paint"); if (root_layer_->needs_painting()) diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index 25a8e072cfa21..5ddebd088de9e 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -13,6 +13,9 @@ #include "flutter/flow/layers/layer.h" #include "lib/fxl/macros.h" #include "lib/fxl/time/time_delta.h" +#if defined(OS_FUCHSIA) +#include +#endif #include "third_party/skia/include/core/SkSize.h" namespace flow { @@ -23,10 +26,24 @@ class LayerTree { ~LayerTree(); + // Raster includes both Preroll and Paint. + void Raster(CompositorContext::ScopedFrame& frame, +#if defined(OS_FUCHSIA) + gfx::Metrics* metrics, +#endif + bool ignore_raster_cache = false); + void Preroll(CompositorContext::ScopedFrame& frame, +#if defined(OS_FUCHSIA) + gfx::Metrics* metrics, +#endif bool ignore_raster_cache = false); #if defined(OS_FUCHSIA) + void set_device_pixel_ratio(float device_pixel_ratio) { + device_pixel_ratio_ = device_pixel_ratio; + } + void UpdateScene(SceneUpdateContext& context, scenic_lib::ContainerNode& container); #endif @@ -76,6 +93,10 @@ class LayerTree { bool checkerboard_raster_cache_images_; bool checkerboard_offscreen_layers_; +#if defined(OS_FUCHSIA) + float device_pixel_ratio_ = 1.f; +#endif + FXL_DISALLOW_COPY_AND_ASSIGN(LayerTree); }; diff --git a/flow/layers/performance_overlay_layer.cc b/flow/layers/performance_overlay_layer.cc index 7d871af33b94f..cc55500115a08 100644 --- a/flow/layers/performance_overlay_layer.cc +++ b/flow/layers/performance_overlay_layer.cc @@ -57,6 +57,34 @@ void VisualizeStopWatch(SkCanvas& canvas, } } +void VisualizeCounterValuesBytes(SkCanvas& canvas, + const CounterValues& counter_values, + SkScalar x, + SkScalar y, + SkScalar width, + SkScalar height, + bool show_graph, + bool show_labels, + const std::string& label_prefix) { + const int label_x = 8; // distance from x + const int label_y = -10; // distance from y+height + + if (show_graph) { + SkRect visualization_rect = SkRect::MakeXYWH(x, y, width, height); + counter_values.Visualize(canvas, visualization_rect); + } + + auto current_usage = counter_values.GetCurrentValue(); + + if (show_labels && current_usage > 0) { + std::stringstream stream; + stream.setf(std::ios::fixed | std::ios::showpoint); + stream << std::setprecision(2); + stream << label_prefix << " " << current_usage * 1e-6 << " MB"; + DrawStatisticsText(canvas, stream.str(), x + label_x, y + height + label_y); + } +} + } // namespace PerformanceOverlayLayer::PerformanceOverlayLayer(uint64_t options) @@ -83,6 +111,11 @@ void PerformanceOverlayLayer::Paint(PaintContext& context) const { VisualizeStopWatch(context.canvas, context.engine_time, x, y + height, width, height - padding, options_ & kVisualizeEngineStatistics, options_ & kDisplayEngineStatistics, "UI"); + + VisualizeCounterValuesBytes( + context.canvas, context.memory_usage, x, y + (2 * height), width, + height - padding, options_ & kVisualizeMemoryStatistics, + options_ & kDisplayMemoryStatistics, "Memory (Resident)"); } } // namespace flow diff --git a/flow/layers/performance_overlay_layer.h b/flow/layers/performance_overlay_layer.h index 77448107147a4..e7c3ac530a02a 100644 --- a/flow/layers/performance_overlay_layer.h +++ b/flow/layers/performance_overlay_layer.h @@ -14,6 +14,8 @@ const int kDisplayRasterizerStatistics = 1 << 0; const int kVisualizeRasterizerStatistics = 1 << 1; const int kDisplayEngineStatistics = 1 << 2; const int kVisualizeEngineStatistics = 1 << 3; +const int kDisplayMemoryStatistics = 1 << 4; +const int kVisualizeMemoryStatistics = 1 << 5; class PerformanceOverlayLayer : public Layer { public: diff --git a/flow/layers/picture_layer.cc b/flow/layers/picture_layer.cc index 552ca0443bd80..4a99d7d07f75e 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -4,30 +4,39 @@ #include "flutter/flow/layers/picture_layer.h" +#include "flutter/common/threads.h" #include "lib/fxl/logging.h" namespace flow { PictureLayer::PictureLayer() = default; -PictureLayer::~PictureLayer() = default; +PictureLayer::~PictureLayer() { + // The picture may contain references to textures that are associated + // with the IO thread's context. + SkPicture* picture = picture_.release(); + if (picture) { + blink::Threads::IO()->PostTask([picture]() { picture->unref(); }); + } +} void PictureLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { - SkPicture* sk_picture = picture(); - if (auto cache = context->raster_cache) { raster_cache_result_ = cache->GetPrerolledImage( - context->gr_context, sk_picture, matrix, context->dst_color_space, + context->gr_context, picture_.get(), matrix, context->dst_color_space, +#if defined(OS_FUCHSIA) + context->metrics, +#endif is_complex_, will_change_); } - SkRect bounds = sk_picture->cullRect().makeOffset(offset_.x(), offset_.y()); + SkRect bounds = picture_->cullRect().makeOffset(offset_.x(), offset_.y()); set_paint_bounds(bounds); } void PictureLayer::Paint(PaintContext& context) const { TRACE_EVENT0("flutter", "PictureLayer::Paint"); - FXL_DCHECK(picture_.get()); + FXL_DCHECK(picture_); FXL_DCHECK(needs_painting()); SkAutoCanvasRestore save(&context.canvas, true); @@ -44,7 +53,7 @@ void PictureLayer::Paint(PaintContext& context) const { SkCanvas::kStrict_SrcRectConstraint // source constraint ); } else { - context.canvas.drawPicture(picture()); + context.canvas.drawPicture(picture_.get()); } } diff --git a/flow/layers/picture_layer.h b/flow/layers/picture_layer.h index c67929b7cb455..191ef9d7097a2 100644 --- a/flow/layers/picture_layer.h +++ b/flow/layers/picture_layer.h @@ -5,11 +5,8 @@ #ifndef FLUTTER_FLOW_LAYERS_PICTURE_LAYER_H_ #define FLUTTER_FLOW_LAYERS_PICTURE_LAYER_H_ -#include - #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" -#include "flutter/flow/skia_gpu_object.h" namespace flow { @@ -19,14 +16,12 @@ class PictureLayer : public Layer { ~PictureLayer() override; void set_offset(const SkPoint& offset) { offset_ = offset; } - void set_picture(SkiaGPUObject picture) { - picture_ = std::move(picture); - } + void set_picture(sk_sp picture) { picture_ = std::move(picture); } void set_is_complex(bool value) { is_complex_ = value; } void set_will_change(bool value) { will_change_ = value; } - SkPicture* picture() const { return picture_.get().get(); } + SkPicture* picture() const { return picture_.get(); } void Preroll(PrerollContext* frame, const SkMatrix& matrix) override; @@ -34,9 +29,7 @@ class PictureLayer : public Layer { private: SkPoint offset_; - // Even though pictures themselves are not GPU resources, they may reference - // images that have a reference to a GPU resource. - SkiaGPUObject picture_; + sk_sp picture_; bool is_complex_ = false; bool will_change_ = false; RasterCacheResult raster_cache_result_; diff --git a/flow/process_info.h b/flow/process_info.h new file mode 100644 index 0000000000000..6623fe7257396 --- /dev/null +++ b/flow/process_info.h @@ -0,0 +1,31 @@ +// Copyright 2016 The Chromium 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_FLOW_PROCESS_INFO_H_ +#define FLUTTER_FLOW_PROCESS_INFO_H_ + +#include "lib/fxl/macros.h" + +namespace flow { + +/// The CompositorContext attempts to collect information from the process for +/// instrumentation purposes. The compositor does not have the platform +/// specific capabilities to collect this information on its own. The platform +/// can choose to provide this information however. +class ProcessInfo { + public: + virtual ~ProcessInfo() = default; + + virtual bool SampleNow() = 0; + + /// Virtual memory size in bytes. + virtual size_t GetVirtualMemorySize() = 0; + + /// Resident memory size in bytes. + virtual size_t GetResidentMemorySize() = 0; +}; + +} // namespace flow + +#endif // FLUTTER_FLOW_PROCESS_INFO_H_ diff --git a/flow/raster_cache.cc b/flow/raster_cache.cc index 11a86729b489b..aa9fad0e281de 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -6,6 +6,7 @@ #include +#include "flutter/common/threads.h" #include "flutter/flow/paint_utils.h" #include "flutter/glue/trace_event.h" #include "lib/fxl/logging.h" @@ -72,6 +73,9 @@ RasterCacheResult RasterizePicture(SkPicture* picture, GrContext* context, const MatrixDecomposition& matrix, SkColorSpace* dst_color_space, +#if defined(OS_FUCHSIA) + gfx::Metrics* metrics, +#endif bool checkerboard) { TRACE_EVENT0("flutter", "RasterCachePopulate"); @@ -79,9 +83,17 @@ RasterCacheResult RasterizePicture(SkPicture* picture, const SkRect logical_rect = picture->cullRect(); - const SkRect physical_rect = - SkRect::MakeWH(std::fabs(logical_rect.width() * scale.x()), - std::fabs(logical_rect.height() * scale.y())); +#if defined(OS_FUCHSIA) + float metrics_scale_x = metrics->scale_x; + float metrics_scale_y = metrics->scale_y; +#else + float metrics_scale_x = 1.f; + float metrics_scale_y = 1.f; +#endif + + const SkRect physical_rect = SkRect::MakeWH( + std::fabs(logical_rect.width() * metrics_scale_x * scale.x()), + std::fabs(logical_rect.height() * metrics_scale_y * scale.y())); const SkImageInfo image_info = SkImageInfo::MakeN32Premul( std::ceil(physical_rect.width()), // physical width @@ -108,7 +120,8 @@ RasterCacheResult RasterizePicture(SkPicture* picture, } canvas->clear(SK_ColorTRANSPARENT); - canvas->scale(std::abs(scale.x()), std::abs(scale.y())); + canvas->scale(std::abs(scale.x() * metrics_scale_x), + std::abs(scale.y() * metrics_scale_y)); canvas->translate(-logical_rect.left(), -logical_rect.top()); canvas->drawPicture(picture); @@ -140,6 +153,9 @@ RasterCacheResult RasterCache::GetPrerolledImage( SkPicture* picture, const SkMatrix& transformation_matrix, SkColorSpace* dst_color_space, +#if defined(OS_FUCHSIA) + gfx::Metrics* metrics, +#endif bool is_complex, bool will_change) { if (!IsPictureWorthRasterizing(picture, will_change, is_complex)) { @@ -156,7 +172,11 @@ RasterCacheResult RasterCache::GetPrerolledImage( return {}; } - RasterCacheKey cache_key(*picture, matrix); + RasterCacheKey cache_key(*picture, +#if defined(OS_FUCHSIA) + metrics->scale_x, metrics->scale_y, +#endif + matrix); Entry& entry = cache_[cache_key]; entry.access_count = ClampSize(entry.access_count + 1, 0, threshold_); @@ -169,6 +189,9 @@ RasterCacheResult RasterCache::GetPrerolledImage( if (!entry.image.is_valid()) { entry.image = RasterizePicture(picture, context, matrix, dst_color_space, +#if defined(OS_FUCHSIA) + metrics, +#endif checkerboard_images_); } diff --git a/flow/raster_cache.h b/flow/raster_cache.h index 3278eb355b030..31201049b6119 100644 --- a/flow/raster_cache.h +++ b/flow/raster_cache.h @@ -12,6 +12,9 @@ #include "flutter/flow/raster_cache_key.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/weak_ptr.h" +#if defined(OS_FUCHSIA) +#include +#endif #include "third_party/skia/include/core/SkImage.h" #include "third_party/skia/include/core/SkSize.h" @@ -54,6 +57,9 @@ class RasterCache { SkPicture* picture, const SkMatrix& transformation_matrix, SkColorSpace* dst_color_space, +#if defined(OS_FUCHSIA) + gfx::Metrics* metrics, +#endif bool is_complex, bool will_change); diff --git a/flow/raster_cache_key.h b/flow/raster_cache_key.h index 1f28ea5320d36..83df52658c981 100644 --- a/flow/raster_cache_key.h +++ b/flow/raster_cache_key.h @@ -15,15 +15,30 @@ namespace flow { class RasterCacheKey { public: - RasterCacheKey(const SkPicture& picture, const MatrixDecomposition& matrix) + RasterCacheKey(const SkPicture& picture, +#if defined(OS_FUCHSIA) + float metrics_scale_x, + float metrics_scale_y, +#endif + const MatrixDecomposition& matrix) : picture_id_(picture.uniqueID()), - scale_key_(SkISize::Make(matrix.scale().x() * 1e3, - matrix.scale().y() * 1e3)) {} +#if defined(OS_FUCHSIA) + metrics_scale_x_(metrics_scale_x), + metrics_scale_y_(metrics_scale_y), +#endif + scale_key_( + SkISize::Make(matrix.scale().x() * 1e3, matrix.scale().y() * 1e3)) { + } uint32_t picture_id() const { return picture_id_; } const SkISize& scale_key() const { return scale_key_; } +#if defined(OS_FUCHSIA) + float metrics_scale_x() const { return metrics_scale_x_; } + float metrics_scale_y() const { return metrics_scale_y_; } +#endif + struct Hash { std::size_t operator()(RasterCacheKey const& key) const { return key.picture_id_; @@ -34,6 +49,11 @@ class RasterCacheKey { constexpr bool operator()(const RasterCacheKey& lhs, const RasterCacheKey& rhs) const { return lhs.picture_id_ == rhs.picture_id_ && +#if defined(OS_FUCHSIA) + lhs.metrics_scale_x_ == rhs.metrics_scale_x_ && + + lhs.metrics_scale_y_ == rhs.metrics_scale_y_ && +#endif lhs.scale_key_ == rhs.scale_key_; } }; @@ -43,6 +63,10 @@ class RasterCacheKey { private: uint32_t picture_id_; +#if defined(OS_FUCHSIA) + float metrics_scale_x_; + float metrics_scale_y_; +#endif SkISize scale_key_; }; diff --git a/flow/scene_update_context.cc b/flow/scene_update_context.cc index b9d6801cc82ee..83883c508b4df 100644 --- a/flow/scene_update_context.cc +++ b/flow/scene_update_context.cc @@ -4,6 +4,7 @@ #include "flutter/flow/scene_update_context.h" +#include "flutter/common/threads.h" #include "flutter/flow/export_node.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/matrix_decomposition.h" @@ -18,7 +19,9 @@ SceneUpdateContext::SceneUpdateContext(scenic_lib::Session* session, } SceneUpdateContext::~SceneUpdateContext() { - // Release Mozart session resources for all ExportNodes. + ASSERT_IS_GPU_THREAD; + + // Release Scenic session resources for all ExportNodes. for (auto export_node : export_nodes_) { export_node->Dispose(false); } @@ -27,16 +30,21 @@ SceneUpdateContext::~SceneUpdateContext() { void SceneUpdateContext::AddChildScene(ExportNode* export_node, SkPoint offset, bool hit_testable) { + ASSERT_IS_GPU_THREAD; FXL_DCHECK(top_entity_); export_node->Bind(*this, top_entity_->entity_node(), offset, hit_testable); } void SceneUpdateContext::AddExportNode(ExportNode* export_node) { + ASSERT_IS_GPU_THREAD; + export_nodes_.insert(export_node); // Might already have been added. } void SceneUpdateContext::RemoveExportNode(ExportNode* export_node) { + ASSERT_IS_GPU_THREAD; + export_nodes_.erase(export_node); } @@ -187,9 +195,12 @@ SceneUpdateContext::ExecutePaintTasks(CompositorContext::ScopedFrame& frame) { for (auto& task : paint_tasks_) { FXL_DCHECK(task.surface); SkCanvas* canvas = task.surface->GetSkiaSurface()->getCanvas(); - Layer::PaintContext context = {*canvas, frame.context().frame_time(), + Layer::PaintContext context = {*canvas, + frame.context().frame_time(), frame.context().engine_time(), - frame.context().texture_registry(), false}; + frame.context().memory_usage(), + frame.context().texture_registry(), + false}; canvas->restoreToCount(1); canvas->save(); canvas->clear(task.background_color); diff --git a/flow/skia_gpu_object.cc b/flow/skia_gpu_object.cc deleted file mode 100644 index ce2312f921580..0000000000000 --- a/flow/skia_gpu_object.cc +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/flow/skia_gpu_object.h" - -#include "flutter/fml/message_loop.h" - -namespace flow { - -SkiaUnrefQueue::SkiaUnrefQueue(fxl::RefPtr task_runner, - fxl::TimeDelta delay) - : task_runner_(std::move(task_runner)), - drain_delay_(delay), - drain_pending_(false) {} - -SkiaUnrefQueue::~SkiaUnrefQueue() { - Drain(); -} - -void SkiaUnrefQueue::Unref(SkRefCnt* object) { - std::lock_guard lock(mutex_); - objects_.push_back(object); - if (!drain_pending_) { - drain_pending_ = true; - task_runner_->PostDelayedTask( - [strong = fxl::Ref(this)]() { strong->Drain(); }, drain_delay_); - } -} - -void SkiaUnrefQueue::Drain() { - std::deque skia_objects; - { - std::lock_guard lock(mutex_); - objects_.swap(skia_objects); - drain_pending_ = false; - } - - for (SkRefCnt* skia_object : skia_objects) { - skia_object->unref(); - } -} - -} // namespace flow diff --git a/flow/skia_gpu_object.h b/flow/skia_gpu_object.h deleted file mode 100644 index 4711f80c6f4fd..0000000000000 --- a/flow/skia_gpu_object.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2017 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_FLOW_SKIA_GPU_OBJECT_H_ -#define FLUTTER_FLOW_SKIA_GPU_OBJECT_H_ - -#include -#include - -#include "flutter/fml/memory/weak_ptr.h" -#include "flutter/fml/task_runner.h" -#include "lib/fxl/memory/ref_ptr.h" -#include "third_party/skia/include/core/SkRefCnt.h" - -namespace flow { - -// A queue that holds Skia objects that must be destructed on the the given task -// runner. -class SkiaUnrefQueue : public fxl::RefCountedThreadSafe { - public: - void Unref(SkRefCnt* object); - - // Usually, the drain is called automatically. However, during IO manager - // shutdown (when the platform side reference to the OpenGL context is about - // to go away), we may need to pre-emptively drain the unref queue. It is the - // responsibility of the caller to ensure that no further unrefs are queued - // after this call. - void Drain(); - - private: - const fxl::RefPtr task_runner_; - const fxl::TimeDelta drain_delay_; - std::mutex mutex_; - std::deque objects_; - bool drain_pending_; - - SkiaUnrefQueue(fxl::RefPtr task_runner, - fxl::TimeDelta delay); - - ~SkiaUnrefQueue(); - - FRIEND_REF_COUNTED_THREAD_SAFE(SkiaUnrefQueue); - FRIEND_MAKE_REF_COUNTED(SkiaUnrefQueue); - FXL_DISALLOW_COPY_AND_ASSIGN(SkiaUnrefQueue); -}; - -/// An object whose deallocation needs to be performed on an specific unref -/// queue. The template argument U need to have a call operator that returns -/// that unref queue. -template -class SkiaGPUObject { - public: - using SkiaObjectType = T; - - SkiaGPUObject() = default; - - SkiaGPUObject(sk_sp object, fxl::RefPtr queue) - : object_(std::move(object)), queue_(std::move(queue)) { - FXL_DCHECK(queue_ && object_); - } - - SkiaGPUObject(SkiaGPUObject&&) = default; - - ~SkiaGPUObject() { reset(); } - - SkiaGPUObject& operator=(SkiaGPUObject&&) = default; - - sk_sp get() const { return object_; } - - void reset() { - if (object_) { - queue_->Unref(object_.release()); - } - queue_ = nullptr; - FXL_DCHECK(object_ == nullptr); - } - - private: - sk_sp object_; - fxl::RefPtr queue_; - - FXL_DISALLOW_COPY_AND_ASSIGN(SkiaGPUObject); -}; - -} // namespace flow - -#endif // FLUTTER_FLOW_SKIA_GPU_OBJECT_H_ diff --git a/flow/texture.cc b/flow/texture.cc index d5cc3ae228aa7..33a48af989477 100644 --- a/flow/texture.cc +++ b/flow/texture.cc @@ -11,32 +11,36 @@ TextureRegistry::TextureRegistry() = default; TextureRegistry::~TextureRegistry() = default; void TextureRegistry::RegisterTexture(std::shared_ptr texture) { + ASSERT_IS_GPU_THREAD mapping_[texture->Id()] = texture; } void TextureRegistry::UnregisterTexture(int64_t id) { + ASSERT_IS_GPU_THREAD mapping_.erase(id); } void TextureRegistry::OnGrContextCreated() { + ASSERT_IS_GPU_THREAD; for (auto& it : mapping_) { it.second->OnGrContextCreated(); } } void TextureRegistry::OnGrContextDestroyed() { + ASSERT_IS_GPU_THREAD; for (auto& it : mapping_) { it.second->OnGrContextDestroyed(); } } std::shared_ptr TextureRegistry::GetTexture(int64_t id) { + ASSERT_IS_GPU_THREAD auto it = mapping_.find(id); return it != mapping_.end() ? it->second : nullptr; } Texture::Texture(int64_t id) : id_(id) {} - Texture::~Texture() = default; } // namespace flow diff --git a/flow/texture.h b/flow/texture.h index f5e4430834084..a602a6b45b5b4 100644 --- a/flow/texture.h +++ b/flow/texture.h @@ -6,7 +6,7 @@ #define FLUTTER_FLOW_TEXTURE_H_ #include - +#include "flutter/common/threads.h" #include "lib/fxl/synchronization/waitable_event.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -29,9 +29,6 @@ class Texture { // Called from GPU thread. virtual void OnGrContextDestroyed() = 0; - // Called on GPU thread. - virtual void MarkNewFrameAvailable() = 0; - int64_t Id() { return id_; } private: diff --git a/fml/BUILD.gn b/fml/BUILD.gn index ffbf949cc0957..6dabcb446c912 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -4,12 +4,9 @@ source_set("fml") { sources = [ - "file.h", "icu_util.cc", "icu_util.h", - "mapping.cc", "mapping.h", - "memory/thread_checker.h", "memory/weak_ptr.h", "memory/weak_ptr_internal.cc", "memory/weak_ptr_internal.h", @@ -17,9 +14,8 @@ source_set("fml") { "message_loop.h", "message_loop_impl.cc", "message_loop_impl.h", - "native_library.h", - "paths.cc", "paths.h", + "task_observer.h", "task_runner.cc", "task_runner.h", "thread.cc", @@ -27,9 +23,6 @@ source_set("fml") { "thread_local.h", "trace_event.cc", "trace_event.h", - "unique_fd.cc", - "unique_fd.h", - "unique_object.h", ] deps = [ @@ -102,25 +95,16 @@ source_set("fml") { ] } - if (is_fuchsia) { - sources += [ "platform/fuchsia/paths_fuchsia.cc" ] - } - if (is_win) { sources += [ - "platform/win/file_win.cc", "platform/win/mapping_win.cc", "platform/win/message_loop_win.cc", "platform/win/message_loop_win.h", - "platform/win/native_library_win.cc", "platform/win/paths_win.cc", - "platform/win/wstring_conversion.h", ] } else { sources += [ - "platform/posix/file_posix.cc", "platform/posix/mapping_posix.cc", - "platform/posix/native_library_posix.cc", ] } } diff --git a/fml/file.h b/fml/file.h deleted file mode 100644 index 2327b2eef831e..0000000000000 --- a/fml/file.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 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_FML_FILE_H_ -#define FLUTTER_FML_FILE_H_ - -#include "flutter/fml/unique_fd.h" -#include "lib/fxl/macros.h" - -namespace fml { - -enum class OpenPermission { - kRead = 1, - kWrite = 1 << 1, - kReadWrite = kRead | kWrite, - kExecute, -}; - -fml::UniqueFD OpenFile(const char* path, - OpenPermission permission, - bool is_directory = false); - -fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory, - const char* path, - OpenPermission permission, - bool is_directory = false); - -fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor); - -bool IsDirectory(const fml::UniqueFD& directory); - -} // namespace fml - -#endif // FLUTTER_FML_FILE_H_ diff --git a/fml/icu_util.cc b/fml/icu_util.cc index 0c0acd06dbbdf..093dc3d02b1bc 100644 --- a/fml/icu_util.cc +++ b/fml/icu_util.cc @@ -22,6 +22,8 @@ static constexpr char kPathSeparator = '\\'; static constexpr char kPathSeparator = '/'; #endif +static constexpr char kIcuDataFileName[] = "icudtl.dat"; + class ICUContext { public: ICUContext(const std::string& icu_data_path) : valid_(false) { @@ -32,15 +34,15 @@ class ICUContext { bool SetupMapping(const std::string& icu_data_path) { // Check if the explicit path specified exists. - auto path_mapping = std::make_unique(icu_data_path, false); - if (path_mapping->GetSize() != 0) { - mapping_ = std::move(path_mapping); + auto overriden_path_mapping = std::make_unique(icu_data_path); + if (overriden_path_mapping->GetSize() != 0) { + mapping_ = std::move(overriden_path_mapping); return true; } // Check to see if the mapping is in the resources bundle. if (PlatformHasResourcesBundle()) { - auto resource = GetResourceMapping(icu_data_path); + auto resource = GetResourceMapping(kIcuDataFileName); if (resource != nullptr && resource->GetSize() != 0) { mapping_ = std::move(resource); return true; @@ -55,8 +57,10 @@ class ICUContext { return false; } + // FIXME(chinmaygarde): There is no Path::Join in FXL. So a non-portable + // version is used here. Patch FXL and update. auto file = std::make_unique( - directory.second + kPathSeparator + icu_data_path, false); + directory.second + kPathSeparator + kIcuDataFileName); if (file->GetSize() != 0) { mapping_ = std::move(file); return true; @@ -92,8 +96,7 @@ class ICUContext { void InitializeICUOnce(const std::string& icu_data_path) { static ICUContext* context = new ICUContext(icu_data_path); - FXL_CHECK(context->IsValid()) - << "Must be able to initialize the ICU context. Tried: " << icu_data_path; + FXL_CHECK(context->IsValid()) << "Must be able to initialize the ICU context"; } std::once_flag g_icu_init_flag; diff --git a/fml/macros.h b/fml/macros.h deleted file mode 100644 index ba46b9dda4b4d..0000000000000 --- a/fml/macros.h +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2018 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_FML_MACROS_H_ -#define FLUTTER_FML_MACROS_H_ - -#include "lib/fxl/macros.h" - -#ifndef FML_USED_ON_EMBEDDER - -#define FML_EMBEDDER_ONLY [[deprecated]] - -#else // FML_USED_ON_EMBEDDER - -#define FML_EMBEDDER_ONLY - -#endif // FML_USED_ON_EMBEDDER - -#endif // FLUTTER_FML_MACROS_H_ diff --git a/fml/mapping.cc b/fml/mapping.cc deleted file mode 100644 index 97d7905015f61..0000000000000 --- a/fml/mapping.cc +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/fml/mapping.h" - -namespace fml { - -DataMapping::DataMapping(std::vector data) : data_(std::move(data)) {} - -DataMapping::~DataMapping() = default; - -size_t DataMapping::GetSize() const { - return data_.size(); -} - -const uint8_t* DataMapping::GetMapping() const { - return data_.data(); -} -} // namespace fml diff --git a/fml/mapping.h b/fml/mapping.h index 00e9685dd6b0c..8963b22a9c1f6 100644 --- a/fml/mapping.h +++ b/fml/mapping.h @@ -7,10 +7,14 @@ #include #include -#include -#include "flutter/fml//unique_fd.h" #include "lib/fxl/build_config.h" + +#if OS_WIN +#include +#endif + +#include "lib/fxl/files/unique_fd.h" #include "lib/fxl/macros.h" namespace fml { @@ -35,9 +39,12 @@ std::unique_ptr GetResourceMapping(const std::string& resource_name); class FileMapping : public Mapping { public: - FileMapping(const std::string& path, bool executable = false); + FileMapping(const std::string& path); - FileMapping(const fml::UniqueFD& fd, bool executable = false); +// fxl::UniqueFD isn't supported for Windows handles. +#if !OS_WIN + FileMapping(const fxl::UniqueFD& fd); +#endif ~FileMapping() override; @@ -46,32 +53,16 @@ class FileMapping : public Mapping { const uint8_t* GetMapping() const override; private: - size_t size_ = 0; - uint8_t* mapping_ = nullptr; + size_t size_; + uint8_t* mapping_; #if OS_WIN - fml::UniqueFD mapping_handle_; + HANDLE mapping_handle_; #endif FXL_DISALLOW_COPY_AND_ASSIGN(FileMapping); }; -class DataMapping : public Mapping { - public: - DataMapping(std::vector data); - - ~DataMapping() override; - - size_t GetSize() const override; - - const uint8_t* GetMapping() const override; - - private: - std::vector data_; - - FXL_DISALLOW_COPY_AND_ASSIGN(DataMapping); -}; - } // namespace fml #endif // FLUTTER_FML_MAPPING_H_ diff --git a/fml/memory/thread_checker.h b/fml/memory/thread_checker.h deleted file mode 100644 index f22e9d1cfaf06..0000000000000 --- a/fml/memory/thread_checker.h +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2016 The Fuchsia Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// A class for checking that the current thread is/isn't the same as an initial -// thread. - -#ifndef FLUTTER_FML_MEMORY_THREAD_CHECKER_H_ -#define FLUTTER_FML_MEMORY_THREAD_CHECKER_H_ - -#include "lib/fxl/build_config.h" - -#if defined(OS_WIN) -#include -#else -#include -#endif - -#include "lib/fxl/logging.h" -#include "lib/fxl/macros.h" - -namespace fml { - -// A simple class that records the identity of the thread that it was created -// on, and at later points can tell if the current thread is the same as its -// creation thread. This class is thread-safe. -// -// Note: Unlike Chromium's |base::ThreadChecker|, this is *not* Debug-only (so -// #ifdef it out if you want something Debug-only). (Rationale: Having a -// |CalledOnValidThread()| that lies in Release builds seems bad. Moreover, -// there's a small space cost to having even an empty class. ) -class ThreadChecker final { - public: -#if defined(OS_WIN) - ThreadChecker() : self_(GetCurrentThreadId()) {} - ~ThreadChecker() {} - - bool IsCreationThreadCurrent() const { return GetCurrentThreadId() == self_; } - - private: - DWORD self_; - -#else - ThreadChecker() : self_(pthread_self()) {} - ~ThreadChecker() {} - - // Returns true if the current thread is the thread this object was created - // on and false otherwise. - bool IsCreationThreadCurrent() const { - return !!pthread_equal(pthread_self(), self_); - } - - private: - pthread_t self_; -#endif -}; - -#ifndef NDEBUG -#define FML_DECLARE_THREAD_CHECKER(c) fml::ThreadChecker c -#define FML_DCHECK_CREATION_THREAD_IS_CURRENT(c) \ - FXL_DCHECK((c).IsCreationThreadCurrent()) -#else -#define FML_DECLARE_THREAD_CHECKER(c) -#define FML_DCHECK_CREATION_THREAD_IS_CURRENT(c) ((void)0) -#endif - -} // namespace fml - -#endif // FLUTTER_FML_MEMORY_THREAD_CHECKER_H_ diff --git a/fml/memory/weak_ptr.h b/fml/memory/weak_ptr.h index 2b369952d7306..5b85c531966b2 100644 --- a/fml/memory/weak_ptr.h +++ b/fml/memory/weak_ptr.h @@ -10,17 +10,12 @@ #include -#include "flutter/fml/memory/thread_checker.h" #include "flutter/fml/memory/weak_ptr_internal.h" #include "lib/fxl/logging.h" #include "lib/fxl/memory/ref_counted.h" namespace fml { -struct DebugThreadChecker { - FML_DECLARE_THREAD_CHECKER(checker); -}; - // Forward declaration, so |WeakPtr| can friend it. template class WeakPtrFactory; @@ -46,17 +41,13 @@ class WeakPtr { WeakPtr(const WeakPtr& r) = default; template - WeakPtr(const WeakPtr& r) - : ptr_(static_cast(r.ptr_)), flag_(r.flag_), checker_(r.checker_) {} + WeakPtr(const WeakPtr& r) : ptr_(r.ptr_), flag_(r.flag_) {} // Move constructor. WeakPtr(WeakPtr&& r) = default; template - WeakPtr(WeakPtr&& r) - : ptr_(static_cast(r.ptr_)), - flag_(std::move(r.flag_)), - checker_(r.checker_) {} + WeakPtr(WeakPtr&& r) : ptr_(r.ptr_), flag_(std::move(r.flag_)) {} ~WeakPtr() = default; @@ -74,24 +65,16 @@ class WeakPtr { // The following methods should only be called on the same thread as the // "originating" |WeakPtrFactory|. - explicit operator bool() const { - FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); - return flag_ && flag_->is_valid(); - } + explicit operator bool() const { return flag_ && flag_->is_valid(); } - T* get() const { - FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); - return *this ? ptr_ : nullptr; - } + T* get() const { return *this ? ptr_ : nullptr; } T& operator*() const { - FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); FXL_DCHECK(*this); return *get(); } T* operator->() const { - FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); FXL_DCHECK(*this); return get(); } @@ -102,14 +85,11 @@ class WeakPtr { friend class WeakPtrFactory; - explicit WeakPtr(T* ptr, - fxl::RefPtr&& flag, - DebugThreadChecker checker) - : ptr_(ptr), flag_(std::move(flag)), checker_(checker) {} + explicit WeakPtr(T* ptr, fxl::RefPtr&& flag) + : ptr_(ptr), flag_(std::move(flag)) {} T* ptr_; fxl::RefPtr flag_; - DebugThreadChecker checker_; // Copy/move construction/assignment supported. }; @@ -160,22 +140,19 @@ template class WeakPtrFactory { public: explicit WeakPtrFactory(T* ptr) : ptr_(ptr) { FXL_DCHECK(ptr_); } - ~WeakPtrFactory() { InvalidateWeakPtrs(); } // Gets a new weak pointer, which will be valid until either // |InvalidateWeakPtrs()| is called or this object is destroyed. WeakPtr GetWeakPtr() { - FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); if (!flag_) flag_ = fxl::MakeRefCounted(); - return WeakPtr(ptr_, flag_.Clone(), checker_); + return WeakPtr(ptr_, flag_.Clone()); } // Call this method to invalidate all existing weak pointers. (Note that // additional weak pointers can be produced even after this is called.) void InvalidateWeakPtrs() { - FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); if (!flag_) return; flag_->Invalidate(); @@ -185,17 +162,13 @@ class WeakPtrFactory { // Call this method to determine if any weak pointers exist. (Note that a // "false" result is definitive, but a "true" result may not be if weak // pointers are held/reset/destroyed/reassigned on other threads.) - bool HasWeakPtrs() const { - FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); - return flag_ && !flag_->HasOneRef(); - } + bool HasWeakPtrs() const { return flag_ && !flag_->HasOneRef(); } private: // Note: See weak_ptr_internal.h for an explanation of why we store the // pointer here, instead of in the "flag". T* const ptr_; fxl::RefPtr flag_; - DebugThreadChecker checker_; FXL_DISALLOW_COPY_AND_ASSIGN(WeakPtrFactory); }; diff --git a/fml/message_loop.cc b/fml/message_loop.cc index 44a0e307c1dd1..4765cfa76558f 100644 --- a/fml/message_loop.cc +++ b/fml/message_loop.cc @@ -55,7 +55,7 @@ void MessageLoop::Terminate() { loop_->DoTerminate(); } -fxl::RefPtr MessageLoop::GetTaskRunner() const { +fxl::RefPtr MessageLoop::GetTaskRunner() const { return task_runner_; } @@ -63,12 +63,12 @@ fxl::RefPtr MessageLoop::GetLoopImpl() const { return loop_; } -void MessageLoop::AddTaskObserver(intptr_t key, fxl::Closure callback) { - loop_->AddTaskObserver(key, callback); +void MessageLoop::AddTaskObserver(TaskObserver* observer) { + loop_->AddTaskObserver(observer); } -void MessageLoop::RemoveTaskObserver(intptr_t key) { - loop_->RemoveTaskObserver(key); +void MessageLoop::RemoveTaskObserver(TaskObserver* observer) { + loop_->RemoveTaskObserver(observer); } void MessageLoop::RunExpiredTasksNow() { diff --git a/fml/message_loop.h b/fml/message_loop.h index 3bfb1c40c6df7..87773619ccc51 100644 --- a/fml/message_loop.h +++ b/fml/message_loop.h @@ -5,7 +5,7 @@ #ifndef FLUTTER_FML_MESSAGE_LOOP_H_ #define FLUTTER_FML_MESSAGE_LOOP_H_ -#include "flutter/fml/macros.h" +#include "flutter/fml/task_observer.h" #include "lib/fxl/macros.h" #include "lib/fxl/tasks/task_runner.h" @@ -16,7 +16,6 @@ class MessageLoopImpl; class MessageLoop { public: - FML_EMBEDDER_ONLY static MessageLoop& GetCurrent(); bool IsValid() const; @@ -25,11 +24,11 @@ class MessageLoop { void Terminate(); - void AddTaskObserver(intptr_t key, fxl::Closure callback); + void AddTaskObserver(TaskObserver* observer); - void RemoveTaskObserver(intptr_t key); + void RemoveTaskObserver(TaskObserver* observer); - fxl::RefPtr GetTaskRunner() const; + fxl::RefPtr GetTaskRunner() const; // Exposed for the embedder shell which allows clients to poll for events // instead of dedicating a thread to the message loop. diff --git a/fml/message_loop_impl.cc b/fml/message_loop_impl.cc index df885f3792d5f..cec9b7e448f1a 100644 --- a/fml/message_loop_impl.cc +++ b/fml/message_loop_impl.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include "flutter/fml/message_loop_impl.h" #include @@ -13,29 +11,35 @@ #include "lib/fxl/build_config.h" #if OS_MACOSX + #include "flutter/fml/platform/darwin/message_loop_darwin.h" +using PlatformMessageLoopImpl = fml::MessageLoopDarwin; + #elif OS_ANDROID + #include "flutter/fml/platform/android/message_loop_android.h" +using PlatformMessageLoopImpl = fml::MessageLoopAndroid; + #elif OS_LINUX + #include "flutter/fml/platform/linux/message_loop_linux.h" +using PlatformMessageLoopImpl = fml::MessageLoopLinux; + #elif OS_WIN + #include "flutter/fml/platform/win/message_loop_win.h" +using PlatformMessageLoopImpl = fml::MessageLoopWin; + +#else + +#error This platform does not have a message loop implementation. + #endif namespace fml { fxl::RefPtr MessageLoopImpl::Create() { -#if OS_MACOSX - return fxl::MakeRefCounted(); -#elif OS_ANDROID - return fxl::MakeRefCounted(); -#elif OS_LINUX - return fxl::MakeRefCounted(); -#elif OS_WIN - return fxl::MakeRefCounted(); -#else - return nullptr; -#endif + return fxl::MakeRefCounted<::PlatformMessageLoopImpl>(); } MessageLoopImpl::MessageLoopImpl() : order_(0), terminated_(false) {} @@ -51,19 +55,20 @@ void MessageLoopImpl::RunExpiredTasksNow() { RunExpiredTasks(); } -void MessageLoopImpl::AddTaskObserver(intptr_t key, fxl::Closure callback) { - FXL_DCHECK(callback != nullptr); +void MessageLoopImpl::AddTaskObserver(TaskObserver* observer) { + FXL_DCHECK(observer != nullptr); FXL_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this) << "Message loop task observer must be added on the same thread as the " "loop."; - task_observers_[key] = std::move(callback); + task_observers_.insert(observer); } -void MessageLoopImpl::RemoveTaskObserver(intptr_t key) { +void MessageLoopImpl::RemoveTaskObserver(TaskObserver* observer) { + FXL_DCHECK(observer != nullptr); FXL_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this) << "Message loop task observer must be removed from the same thread as " "the loop."; - task_observers_.erase(key); + task_observers_.erase(observer); } void MessageLoopImpl::DoRun() { @@ -139,7 +144,7 @@ void MessageLoopImpl::RunExpiredTasks() { for (const auto& invocation : invocations) { invocation(); for (const auto& observer : task_observers_) { - observer.second(); + observer->DidProcessTask(); } } } diff --git a/fml/message_loop_impl.h b/fml/message_loop_impl.h index 478cbd1f1a0be..bfdb2064cb264 100644 --- a/fml/message_loop_impl.h +++ b/fml/message_loop_impl.h @@ -7,9 +7,9 @@ #include #include -#include #include #include +#include #include #include "flutter/fml/message_loop.h" @@ -34,9 +34,9 @@ class MessageLoopImpl : public fxl::RefCountedThreadSafe { void PostTask(fxl::Closure task, fxl::TimePoint target_time); - void AddTaskObserver(intptr_t key, fxl::Closure callback); + void AddTaskObserver(TaskObserver* observer); - void RemoveTaskObserver(intptr_t key); + void RemoveTaskObserver(TaskObserver* observer); void DoRun(); @@ -71,7 +71,7 @@ class MessageLoopImpl : public fxl::RefCountedThreadSafe { using DelayedTaskQueue = std:: priority_queue, DelayedTaskCompare>; - std::map task_observers_; + std::set task_observers_; std::mutex delayed_tasks_mutex_; DelayedTaskQueue delayed_tasks_; size_t order_; diff --git a/fml/message_loop_unittests.cc b/fml/message_loop_unittests.cc index cd2acd308b46a..11ea72c3900eb 100644 --- a/fml/message_loop_unittests.cc +++ b/fml/message_loop_unittests.cc @@ -2,12 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include #include "flutter/fml/message_loop.h" -#include "flutter/fml/task_runner.h" #include "gtest/gtest.h" #include "lib/fxl/synchronization/waitable_event.h" @@ -247,6 +244,22 @@ TEST(MessageLoop, TIME_SENSITIVE(MultipleDelayedTasksWithDecreasingDeltas)) { ASSERT_EQ(checked, count); } +class CustomTaskObserver : public fml::TaskObserver { + public: + CustomTaskObserver(std::function lambda) : lambda_(lambda){}; + + ~CustomTaskObserver() override = default; + + void DidProcessTask() override { + if (lambda_) { + lambda_(); + } + }; + + private: + std::function lambda_; +}; + TEST(MessageLoop, TaskObserverFire) { bool started = false; bool terminated = false; @@ -256,7 +269,8 @@ TEST(MessageLoop, TaskObserverFire) { auto& loop = fml::MessageLoop::GetCurrent(); size_t task_count = 0; size_t obs_count = 0; - auto obs = PLATFORM_SPECIFIC_CAPTURE(&obs_count)() { obs_count++; }; + CustomTaskObserver obs( + PLATFORM_SPECIFIC_CAPTURE(&obs_count)() { obs_count++; }); for (size_t i = 0; i < count; i++) { loop.GetTaskRunner()->PostTask( PLATFORM_SPECIFIC_CAPTURE(&terminated, i, &task_count)() { @@ -268,7 +282,7 @@ TEST(MessageLoop, TaskObserverFire) { } }); } - loop.AddTaskObserver(0, obs); + loop.AddTaskObserver(&obs); loop.Run(); ASSERT_EQ(task_count, count); ASSERT_EQ(obs_count, count); diff --git a/fml/native_library.h b/fml/native_library.h deleted file mode 100644 index 7e48ed6d3a3ff..0000000000000 --- a/fml/native_library.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2018 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_FML_NATIVE_LIBRARY_H_ -#define FLUTTER_FML_NATIVE_LIBRARY_H_ - -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/ref_counted.h" -#include "lib/fxl/memory/ref_ptr.h" - -#if OS_WIN - -#include - -#endif // OS_WIN - -namespace fml { -class NativeLibrary : public fxl::RefCountedThreadSafe { - public: -#if OS_WIN - using Handle = HMODULE; -#else // OS_WIN - using Handle = void*; -#endif // OS_WIN - - static fxl::RefPtr Create(const char* path); - - static fxl::RefPtr CreateForCurrentProcess(); - - const uint8_t* ResolveSymbol(const char* symbol); - - private: - Handle handle_ = nullptr; - bool close_handle_ = true; - - NativeLibrary(const char* path); - - NativeLibrary(Handle handle, bool close_handle); - - ~NativeLibrary(); - - Handle GetHandle() const; - - FXL_DISALLOW_COPY_AND_ASSIGN(NativeLibrary); - FRIEND_REF_COUNTED_THREAD_SAFE(NativeLibrary); - FRIEND_MAKE_REF_COUNTED(NativeLibrary); -}; - -} // namespace fml - -#endif // FLUTTER_FML_NATIVE_LIBRARY_H_ diff --git a/fml/paths.cc b/fml/paths.cc deleted file mode 100644 index 9b06b6847f415..0000000000000 --- a/fml/paths.cc +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/fml/paths.h" - -#include "lib/fxl/build_config.h" - -namespace fml { -namespace paths { - -std::string JoinPaths(std::initializer_list components) { - std::stringstream stream; - size_t i = 0; - const size_t size = components.size(); - for (const auto& component : components) { - i++; - stream << component; - if (i != size) { -#if OS_WIN - stream << "\\"; -#else // OS_WIN - stream << "/"; -#endif // OS_WIN - } - } - return stream.str(); -} - -} // namespace paths -} // namespace fml diff --git a/fml/paths.h b/fml/paths.h index 0d4367654de4a..8ec3b4b580476 100644 --- a/fml/paths.h +++ b/fml/paths.h @@ -8,15 +8,11 @@ #include #include -#include "lib/fxl/strings/string_view.h" - namespace fml { namespace paths { std::pair GetExecutableDirectoryPath(); -std::string JoinPaths(std::initializer_list components); - } // namespace paths } // namespace fml diff --git a/fml/platform/android/message_loop_android.h b/fml/platform/android/message_loop_android.h index 19c1eafe79845..e6d04e8253401 100644 --- a/fml/platform/android/message_loop_android.h +++ b/fml/platform/android/message_loop_android.h @@ -10,7 +10,7 @@ #include #include "flutter/fml/message_loop_impl.h" -#include "flutter/fml/unique_fd.h" +#include "lib/fxl/files/unique_fd.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/unique_object.h" @@ -24,8 +24,8 @@ struct UniqueLooperTraits { class MessageLoopAndroid : public MessageLoopImpl { private: - fml::UniqueObject looper_; - fml::UniqueFD timer_fd_; + fxl::UniqueObject looper_; + fxl::UniqueFD timer_fd_; bool running_; MessageLoopAndroid(); diff --git a/fml/platform/darwin/resource_mapping_darwin.mm b/fml/platform/darwin/resource_mapping_darwin.mm index 3ee100121ad0f..5d1b9664e20bc 100644 --- a/fml/platform/darwin/resource_mapping_darwin.mm +++ b/fml/platform/darwin/resource_mapping_darwin.mm @@ -9,8 +9,8 @@ namespace fml { ResourceMappingDarwin::ResourceMappingDarwin(const std::string& resource) - : actual_([[[NSBundle mainBundle] pathForResource:@(resource.c_str()) ofType:nil] UTF8String], - false) {} + : actual_([[[NSBundle mainBundle] pathForResource:@(resource.c_str()) ofType:nil] UTF8String]) { +} ResourceMappingDarwin::~ResourceMappingDarwin() = default; diff --git a/fml/platform/fuchsia/paths_fuchsia.cc b/fml/platform/fuchsia/paths_fuchsia.cc deleted file mode 100644 index 20def9f34fae9..0000000000000 --- a/fml/platform/fuchsia/paths_fuchsia.cc +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/fml/paths.h" - -namespace fml { -namespace paths { - -std::pair GetExecutableDirectoryPath() { - return {false, ""}; -} - -} // namespace paths -} // namespace fml diff --git a/fml/platform/linux/message_loop_linux.h b/fml/platform/linux/message_loop_linux.h index ba5e902d4ac89..51dc690ce887b 100644 --- a/fml/platform/linux/message_loop_linux.h +++ b/fml/platform/linux/message_loop_linux.h @@ -8,15 +8,15 @@ #include #include "flutter/fml/message_loop_impl.h" -#include "flutter/fml/unique_fd.h" +#include "lib/fxl/files/unique_fd.h" #include "lib/fxl/macros.h" namespace fml { class MessageLoopLinux : public MessageLoopImpl { private: - fml::UniqueFD epoll_fd_; - fml::UniqueFD timer_fd_; + fxl::UniqueFD epoll_fd_; + fxl::UniqueFD timer_fd_; bool running_; MessageLoopLinux(); diff --git a/fml/platform/posix/file_posix.cc b/fml/platform/posix/file_posix.cc deleted file mode 100644 index 028f49f4d183d..0000000000000 --- a/fml/platform/posix/file_posix.cc +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/fml/file.h" - -#include -#include -#include - -#include "lib/fxl/files/eintr_wrapper.h" - -namespace fml { - -fml::UniqueFD OpenFile(const char* path, - OpenPermission permission, - bool is_directory) { - return OpenFile(fml::UniqueFD{AT_FDCWD}, path, permission, is_directory); -} - -fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory, - const char* path, - OpenPermission permission, - bool is_directory) { - if (path == nullptr) { - return fml::UniqueFD{}; - } - - int flags = 0; - switch (permission) { - case OpenPermission::kRead: - flags = O_RDONLY; - break; - case OpenPermission::kWrite: - flags = O_WRONLY; - break; - case OpenPermission::kReadWrite: - flags = O_RDWR; - break; - case OpenPermission::kExecute: - flags = O_RDONLY; - break; - } - - if (is_directory) { - flags |= O_DIRECTORY; - } - - return fml::UniqueFD{ - HANDLE_EINTR(::openat(base_directory.get(), path, flags))}; -} - -fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor) { - return fml::UniqueFD{HANDLE_EINTR(::dup(descriptor))}; -} - -bool IsDirectory(const fml::UniqueFD& directory) { - if (!directory.is_valid()) { - return false; - } - - struct stat stat_result = {}; - - if (::fstat(directory.get(), &stat_result) != 0) { - return false; - } - - return S_ISDIR(stat_result.st_mode); -} - -} // namespace fml diff --git a/fml/platform/posix/mapping_posix.cc b/fml/platform/posix/mapping_posix.cc index fc53d6a4f7fc9..07f7edb074ab9 100644 --- a/fml/platform/posix/mapping_posix.cc +++ b/fml/platform/posix/mapping_posix.cc @@ -11,7 +11,6 @@ #include -#include "flutter/fml/unique_fd.h" #include "lib/fxl/build_config.h" #include "lib/fxl/files/eintr_wrapper.h" @@ -40,11 +39,11 @@ std::unique_ptr GetResourceMapping(const std::string& resource_name) { return std::make_unique(resource_name); } -FileMapping::FileMapping(const std::string& path, bool executable) - : FileMapping(fml::UniqueFD{HANDLE_EINTR(::open(path.c_str(), O_RDONLY))}, - executable) {} +FileMapping::FileMapping(const std::string& path) + : FileMapping(fxl::UniqueFD{HANDLE_EINTR(::open(path.c_str(), O_RDONLY))}) { +} -FileMapping::FileMapping(const fml::UniqueFD& handle, bool executable) +FileMapping::FileMapping(const fxl::UniqueFD& handle) : size_(0), mapping_(nullptr) { if (!handle.is_valid()) { return; @@ -60,13 +59,8 @@ FileMapping::FileMapping(const fml::UniqueFD& handle, bool executable) return; } - int flags = PROT_READ; - if (executable) { - flags |= PROT_EXEC; - } - - auto mapping = - ::mmap(nullptr, stat_buffer.st_size, flags, MAP_PRIVATE, handle.get(), 0); + auto mapping = ::mmap(nullptr, stat_buffer.st_size, PROT_READ, MAP_PRIVATE, + handle.get(), 0); if (mapping == MAP_FAILED) { return; diff --git a/fml/platform/posix/native_library_posix.cc b/fml/platform/posix/native_library_posix.cc deleted file mode 100644 index 1255c38fc0821..0000000000000 --- a/fml/platform/posix/native_library_posix.cc +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/fml/native_library.h" - -#include -#include - -namespace fml { - -NativeLibrary::NativeLibrary(const char* path) { - ::dlerror(); - handle_ = ::dlopen(path, RTLD_NOW); - if (handle_ == nullptr) { - FXL_LOG(ERROR) << "Could not open library '" << path << "' due to error '" - << ::dlerror() << "'."; - } -} - -NativeLibrary::NativeLibrary(Handle handle, bool close_handle) - : handle_(handle), close_handle_(close_handle) {} - -NativeLibrary::~NativeLibrary() { - if (handle_ == nullptr) { - return; - } - - if (close_handle_) { - ::dlerror(); - if (::dlclose(handle_) != 0) { - handle_ = nullptr; - FXL_LOG(ERROR) << "Could not close library due to error '" << ::dlerror() - << "'."; - } - } -} - -NativeLibrary::Handle NativeLibrary::GetHandle() const { - return handle_; -} - -fxl::RefPtr NativeLibrary::Create(const char* path) { - auto library = fxl::AdoptRef(new NativeLibrary(path)); - return library->GetHandle() != nullptr ? library : nullptr; -} - -fxl::RefPtr NativeLibrary::CreateForCurrentProcess() { - return fxl::AdoptRef(new NativeLibrary(RTLD_DEFAULT, false)); -} - -const uint8_t* NativeLibrary::ResolveSymbol(const char* symbol) { - auto resolved_symbol = static_cast(::dlsym(handle_, symbol)); - if (resolved_symbol == nullptr) { - FXL_DLOG(ERROR) << "Could not resolve symbol in library: " << symbol; - } - return resolved_symbol; -} - -} // namespace fml diff --git a/fml/platform/win/file_win.cc b/fml/platform/win/file_win.cc deleted file mode 100644 index 3f5e90494b013..0000000000000 --- a/fml/platform/win/file_win.cc +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/fml/file.h" - -#include - -#include - -#include "flutter/fml/platform/win/wstring_conversion.h" - -namespace fml { - -fml::UniqueFD OpenFile(const std::wstring& path, - OpenPermission permission, - bool is_directory) { - if (path.size() == 0) { - return fml::UniqueFD{}; - } - - DWORD desired_access = 0; - - switch (permission) { - case OpenPermission::kRead: - desired_access = GENERIC_READ; - break; - case OpenPermission::kWrite: - desired_access = GENERIC_WRITE; - break; - case OpenPermission::kReadWrite: - desired_access = GENERIC_WRITE | GENERIC_READ; - break; - case OpenPermission::kExecute: - desired_access = GENERIC_READ | GENERIC_EXECUTE; - break; - } - - return fml::UniqueFD{::CreateFile( - path.c_str(), // lpFileName - desired_access, // dwDesiredAccess - FILE_SHARE_READ, // dwShareMode - 0, // lpSecurityAttributes - OPEN_EXISTING, // dwCreationDisposition - FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes - 0 // hTemplateFile - )}; -} - -fml::UniqueFD OpenFile(const char* path, - OpenPermission permission, - bool is_directory) { - return OpenFile(ConvertToWString(path), permission, is_directory); -} - -static std::wstring GetFullHandlePath(const fml::UniqueFD& handle) { - wchar_t buffer[MAX_PATH]; - - DWORD returned = ::GetFinalPathNameByHandle(handle.get(), buffer, MAX_PATH, - FILE_NAME_NORMALIZED); - if (returned == 0 || returned > MAX_PATH) { - return {}; - } - - return {buffer}; -} - -fml::UniqueFD OpenFile(const fml::UniqueFD& base_directory, - const char* path, - OpenPermission permission, - bool is_directory) { - // If the base directory is invalid or the path is absolute, use the generic - // open file variant. - if (!base_directory.is_valid()) { - return OpenFile(path, permission, is_directory); - } - - const auto wpath = ConvertToWString(path); - - if (!::PathIsRelative(wpath.c_str())) { - return OpenFile(path, permission, is_directory); - } - - std::wstringstream stream; - stream << GetFullHandlePath(base_directory) << "\\" << path; - return OpenFile(stream.str(), permission, is_directory); -} - -fml::UniqueFD Duplicate(fml::UniqueFD::element_type descriptor) { - if (descriptor == INVALID_HANDLE_VALUE) { - return fml::UniqueFD{}; - } - - HANDLE duplicated = INVALID_HANDLE_VALUE; - - if (!::DuplicateHandle( - GetCurrentProcess(), // source process - descriptor, // source handle - GetCurrentProcess(), // target process - &duplicated, // target handle - 0, // desired access (ignored because DUPLICATE_SAME_ACCESS) - FALSE, // inheritable - DUPLICATE_SAME_ACCESS) // options - ) { - return fml::UniqueFD{}; - } - - return fml::UniqueFD{duplicated}; -} - -bool IsDirectory(const fml::UniqueFD& directory) { - BY_HANDLE_FILE_INFORMATION info; - if (!::GetFileInformationByHandle(directory.get(), &info)) { - return false; - } - return info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY; -} - -} // namespace fml diff --git a/fml/platform/win/mapping_win.cc b/fml/platform/win/mapping_win.cc index 9dd5dcf6f2249..fd404a14f37dc 100644 --- a/fml/platform/win/mapping_win.cc +++ b/fml/platform/win/mapping_win.cc @@ -5,13 +5,13 @@ #include "flutter/fml/mapping.h" #include -#include -#include #include -#include "flutter/fml/file.h" -#include "flutter/fml/platform/win/wstring_conversion.h" +#include "lib/fxl/build_config.h" + +#include +#include using PlatformResourceMapping = fml::FileMapping; @@ -29,50 +29,47 @@ std::unique_ptr GetResourceMapping(const std::string& resource_name) { return std::make_unique(resource_name); } -FileMapping::FileMapping(const std::string& path, bool executable) - : FileMapping(OpenFile(path.c_str(), - executable ? OpenPermission::kExecute - : OpenPermission::kRead, - false), - executable) {} - -FileMapping::FileMapping(const fml::UniqueFD& fd, bool executable) +FileMapping::FileMapping(const std::string& path) : size_(0), mapping_(nullptr) { - if (!fd.is_valid()) { + HANDLE file_handle_ = + CreateFileA(reinterpret_cast(path.c_str()), GENERIC_READ, + FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr); + + if (file_handle_ == INVALID_HANDLE_VALUE) { return; } - if (auto size = ::GetFileSize(fd.get(), nullptr)) { - if (size > 0) { - size_ = size; - } else { - return; - } + size_ = GetFileSize(file_handle_, nullptr); + if (size_ == INVALID_FILE_SIZE) { + size_ = 0; + return; } - const DWORD protect = executable ? PAGE_EXECUTE_READ : PAGE_READONLY; + mapping_handle_ = CreateFileMapping(file_handle_, nullptr, PAGE_READONLY, 0, + size_, nullptr); - mapping_handle_.reset(::CreateFileMapping(fd.get(), // hFile - nullptr, // lpAttributes - protect, // flProtect - 0, // dwMaximumSizeHigh - 0, // dwMaximumSizeLow - nullptr // lpName - )); + CloseHandle(file_handle_); - if (!mapping_handle_.is_valid()) { + if (mapping_handle_ == INVALID_HANDLE_VALUE) { return; } - const DWORD desired_access = executable ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ; + auto mapping = MapViewOfFile(mapping_handle_, FILE_MAP_READ, 0, 0, size_); + + if (mapping == INVALID_HANDLE_VALUE) { + CloseHandle(mapping_handle_); + mapping_handle_ = INVALID_HANDLE_VALUE; + return; + } - mapping_ = reinterpret_cast( - MapViewOfFile(mapping_handle_.get(), desired_access, 0, 0, size_)); + mapping_ = static_cast(mapping); } FileMapping::~FileMapping() { if (mapping_ != nullptr) { UnmapViewOfFile(mapping_); + CloseHandle(mapping_handle_); } } diff --git a/fml/platform/win/native_library_win.cc b/fml/platform/win/native_library_win.cc deleted file mode 100644 index 6992f06f3e886..0000000000000 --- a/fml/platform/win/native_library_win.cc +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/fml/native_library.h" - -#include - -#include "flutter/fml/platform/win/wstring_conversion.h" - -namespace fml { - -NativeLibrary::NativeLibrary(const char* path) - : handle_(nullptr), close_handle_(true) { - if (path == nullptr) { - return; - } - - handle_ = ::LoadLibrary(ConvertToWString(path).c_str()); -} - -NativeLibrary::NativeLibrary(Handle handle, bool close_handle) - : handle_(handle), close_handle_(close_handle) {} - -NativeLibrary::~NativeLibrary() { - if (handle_ != nullptr && close_handle_) { - ::FreeLibrary(handle_); - } -} - -NativeLibrary::Handle NativeLibrary::GetHandle() const { - return handle_; -} - -fxl::RefPtr NativeLibrary::Create(const char* path) { - auto library = fxl::AdoptRef(new NativeLibrary(path)); - return library->GetHandle() != nullptr ? library : nullptr; -} - -fxl::RefPtr NativeLibrary::CreateForCurrentProcess() { - return fxl::AdoptRef(new NativeLibrary(::GetModuleHandle(nullptr), false)); -} - -const uint8_t* NativeLibrary::ResolveSymbol(const char* symbol) { - if (symbol == nullptr || handle_ == nullptr) { - return nullptr; - } - return reinterpret_cast(::GetProcAddress(handle_, symbol)); -} - -} // namespace fml diff --git a/fml/platform/win/wstring_conversion.h b/fml/platform/win/wstring_conversion.h deleted file mode 100644 index 0682dd84067bf..0000000000000 --- a/fml/platform/win/wstring_conversion.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 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_FML_PLATFORM_WIN_WSTRING_CONVERSION_H_ -#define FLUTTER_FML_PLATFORM_WIN_WSTRING_CONVERSION_H_ - -#include -#include -#include - -namespace fml { - -inline std::wstring ConvertToWString(const char* path) { - if (path == nullptr) { - return {}; - } - std::string path8(path); - std::wstring_convert, wchar_t> wchar_conv; - return wchar_conv.from_bytes(path8); -} - -} // namespace fml - -#endif // FLUTTER_FML_PLATFORM_WIN_WSTRING_CONVERSION_H_ diff --git a/fml/task_observer.h b/fml/task_observer.h new file mode 100644 index 0000000000000..21697cf022005 --- /dev/null +++ b/fml/task_observer.h @@ -0,0 +1,21 @@ +// Copyright 2017 The Chromium 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_FML_TASK_OBSERVER_H_ +#define FLUTTER_FML_TASK_OBSERVER_H_ + +#include "lib/fxl/macros.h" + +namespace fml { + +class TaskObserver { + public: + virtual ~TaskObserver() = default; + + virtual void DidProcessTask() = 0; +}; + +} // namespace fml + +#endif // FLUTTER_FML_TASK_OBSERVER_H_ diff --git a/fml/task_runner.cc b/fml/task_runner.cc index 95f91de8e9124..3d13674d78c11 100644 --- a/fml/task_runner.cc +++ b/fml/task_runner.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include "flutter/fml/task_runner.h" #include @@ -40,14 +38,4 @@ bool TaskRunner::RunsTasksOnCurrentThread() { return MessageLoop::GetCurrent().GetLoopImpl() == loop_; } -void TaskRunner::RunNowOrPostTask(fxl::RefPtr runner, - fxl::Closure task) { - FXL_DCHECK(runner); - if (runner->RunsTasksOnCurrentThread()) { - task(); - } else { - runner->PostTask(std::move(task)); - } -} - } // namespace fml diff --git a/fml/task_runner.h b/fml/task_runner.h index 3b3d2de01639d..20ea85e4e521b 100644 --- a/fml/task_runner.h +++ b/fml/task_runner.h @@ -13,7 +13,7 @@ namespace fml { class MessageLoopImpl; -class TaskRunner final : public fxl::TaskRunner { +class TaskRunner : public fxl::TaskRunner { public: void PostTask(fxl::Closure task) override; @@ -23,15 +23,12 @@ class TaskRunner final : public fxl::TaskRunner { bool RunsTasksOnCurrentThread() override; - static void RunNowOrPostTask(fxl::RefPtr runner, - fxl::Closure task); - private: fxl::RefPtr loop_; TaskRunner(fxl::RefPtr loop); - ~TaskRunner() override; + ~TaskRunner(); FRIEND_MAKE_REF_COUNTED(TaskRunner); FRIEND_REF_COUNTED_THREAD_SAFE(TaskRunner); diff --git a/fml/thread.cc b/fml/thread.cc index de4ee6dd368a8..a1500bfef46a4 100644 --- a/fml/thread.cc +++ b/fml/thread.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include "flutter/fml/thread.h" #include "lib/fxl/build_config.h" @@ -24,7 +22,7 @@ namespace fml { Thread::Thread(const std::string& name) : joined_(false) { fxl::AutoResetWaitableEvent latch; - fxl::RefPtr runner; + fxl::RefPtr runner; thread_ = std::make_unique([&latch, &runner, name]() -> void { SetCurrentThreadName(name); fml::MessageLoop::EnsureInitializedForCurrentThread(); @@ -41,7 +39,7 @@ Thread::~Thread() { Join(); } -fxl::RefPtr Thread::GetTaskRunner() const { +fxl::RefPtr Thread::GetTaskRunner() const { return task_runner_; } @@ -86,8 +84,7 @@ void Thread::SetCurrentThreadName(const std::string& name) { } __except (EXCEPTION_CONTINUE_EXECUTION) { } #else - FXL_DLOG(INFO) << "Could not set the thread name to '" << name - << "' on this platform."; +#error Unsupported Platform #endif } diff --git a/fml/thread.h b/fml/thread.h index 542871f788845..44062f1032116 100644 --- a/fml/thread.h +++ b/fml/thread.h @@ -9,8 +9,8 @@ #include #include -#include "flutter/fml/task_runner.h" #include "lib/fxl/macros.h" +#include "lib/fxl/tasks/task_runner.h" namespace fml { @@ -20,13 +20,13 @@ class Thread { ~Thread(); - fxl::RefPtr GetTaskRunner() const; + fxl::RefPtr GetTaskRunner() const; void Join(); private: std::unique_ptr thread_; - fxl::RefPtr task_runner_; + fxl::RefPtr task_runner_; std::atomic_bool joined_; static void SetCurrentThreadName(const std::string& name); diff --git a/fml/unique_fd.cc b/fml/unique_fd.cc deleted file mode 100644 index bab79f7a9b743..0000000000000 --- a/fml/unique_fd.cc +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/fml/unique_fd.h" - -#include "lib/fxl/files/eintr_wrapper.h" - -namespace fml { -namespace internal { - -#if OS_WIN - -namespace win { - -void UniqueFDTraits::Free(HANDLE fd) { - CloseHandle(fd); -} - -} // namespace win - -#else // OS_WIN - -namespace unix { - -void UniqueFDTraits::Free(int fd) { - IGNORE_EINTR(fd); -} - -} // namespace unix - -#endif // OS_WIN - -} // namespace internal -} // namespace fml diff --git a/fml/unique_fd.h b/fml/unique_fd.h deleted file mode 100644 index 9f2d796579d8c..0000000000000 --- a/fml/unique_fd.h +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2018 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_FML_UNIQUE_FD_H_ -#define FLUTTER_FML_UNIQUE_FD_H_ - -#include "flutter/fml/unique_object.h" -#include "lib/fxl/build_config.h" - -#if OS_WIN - -#include - -#endif // OS_WIN - -namespace fml { -namespace internal { - -#if OS_WIN - -namespace win { - -struct UniqueFDTraits { - static HANDLE InvalidValue() { return INVALID_HANDLE_VALUE; } - static bool IsValid(HANDLE value) { return value != InvalidValue(); } - static void Free(HANDLE fd); -}; - -} // namespace win - -#else // OS_WIN - -namespace unix { - -struct UniqueFDTraits { - static int InvalidValue() { return -1; } - static bool IsValid(int value) { return value >= 0; } - static void Free(int fd); -}; - -} // namespace unix - -#endif // OS_WIN - -} // namespace internal - -#if OS_WIN - -using UniqueFD = UniqueObject; - -#else // OS_WIN - -using UniqueFD = UniqueObject; - -#endif // OS_WIN - -} // namespace fml - -#endif // FLUTTER_FML_UNIQUE_FD_H_ diff --git a/fml/unique_object.h b/fml/unique_object.h deleted file mode 100644 index e2487a53881a9..0000000000000 --- a/fml/unique_object.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 2018 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_FML_UNIQUE_OBJECT_H_ -#define FLUTTER_FML_UNIQUE_OBJECT_H_ - -#include - -#include "lib/fxl/compiler_specific.h" -#include "lib/fxl/logging.h" -#include "lib/fxl/macros.h" - -namespace fml { - -// struct UniqueFooTraits { -// // This function should be fast an inline. -// static int InvalidValue() { return 0; } -// -// // This function should be fast an inline. -// static bool IsValid(const T& value) { return value != InvalidValue(); } -// -// // This free function will not be called if f == InvalidValue()! -// static void Free(int f) { ::FreeFoo(f); } -// }; - -template -class UniqueObject { - private: - // This must be first since it's used inline below. - // - // Use the empty base class optimization to allow us to have a Traits - // member, while avoiding any space overhead for it when Traits is an - // empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good - // discussion of this technique. - struct Data : public Traits { - explicit Data(const T& in) : generic(in) {} - Data(const T& in, const Traits& other) : Traits(other), generic(in) {} - - T generic; - }; - - public: - using element_type = T; - using traits_type = Traits; - - UniqueObject() : data_(Traits::InvalidValue()) {} - explicit UniqueObject(const T& value) : data_(value) {} - - UniqueObject(const T& value, const Traits& traits) : data_(value, traits) {} - - UniqueObject(UniqueObject&& other) - : data_(other.release(), other.get_traits()) {} - - ~UniqueObject() { FreeIfNecessary(); } - - UniqueObject& operator=(UniqueObject&& other) { - reset(other.release()); - return *this; - } - - void reset(const T& value = Traits::InvalidValue()) { - FXL_CHECK(data_.generic == Traits::InvalidValue() || - data_.generic != value); - FreeIfNecessary(); - data_.generic = value; - } - - void swap(UniqueObject& other) { - // Standard swap idiom: 'using std::swap' ensures that std::swap is - // present in the overload set, but we call swap unqualified so that - // any more-specific overloads can be used, if available. - using std::swap; - swap(static_cast(data_), static_cast(other.data_)); - swap(data_.generic, other.data_.generic); - } - - // Release the object. The return value is the current object held by this - // object. After this operation, this object will hold an invalid value, and - // will not own the object any more. - T release() FXL_WARN_UNUSED_RESULT { - T old_generic = data_.generic; - data_.generic = Traits::InvalidValue(); - return old_generic; - } - - const T& get() const { return data_.generic; } - - bool is_valid() const { return Traits::IsValid(data_.generic); } - - bool operator==(const T& value) const { return data_.generic == value; } - - bool operator!=(const T& value) const { return data_.generic != value; } - - Traits& get_traits() { return data_; } - const Traits& get_traits() const { return data_; } - - private: - void FreeIfNecessary() { - if (data_.generic != Traits::InvalidValue()) { - data_.Free(data_.generic); - data_.generic = Traits::InvalidValue(); - } - } - - // Forbid comparison. If U != T, it totally doesn't make sense, and if U == - // T, it still doesn't make sense because you should never have the same - // object owned by two different UniqueObject. - template - bool operator==(const UniqueObject& p2) const = delete; - - template - bool operator!=(const UniqueObject& p2) const = delete; - - Data data_; - - FXL_DISALLOW_COPY_AND_ASSIGN(UniqueObject); -}; - -template -void swap(const UniqueObject& a, const UniqueObject& b) { - a.swap(b); -} - -template -bool operator==(const T& value, const UniqueObject& object) { - return value == object.get(); -} - -template -bool operator!=(const T& value, const UniqueObject& object) { - return !(value == object.get()); -} - -} // namespace fml - -#endif // FLUTTER_FML_UNIQUE_OBJECT_H_ diff --git a/lib/snapshot/BUILD.gn b/lib/snapshot/BUILD.gn index 8c568f4773c90..2b53ffc4d4f6d 100644 --- a/lib/snapshot/BUILD.gn +++ b/lib/snapshot/BUILD.gn @@ -29,40 +29,20 @@ if (is_fuchsia) { # The sole purpose of this target is to generate a .packages file. sources = [] - dot_packages_file = "$target_gen_dir/snapshot.packages" - outputs = [ - dot_packages_file, - ] - deps = [] - foreach(dep, dart_deps) { - deps += [ "$dep($dart_toolchain)" ] - } + infer_package_name = true disable_analysis = true - script = "//build/dart/gen_dot_packages.py" - args = [ - "--out", - rebase_path(dot_packages_file, root_build_dir), - "--source-dir", - rebase_path("."), - "--root-build-dir", - rebase_path(root_build_dir), - "--root-gen-dir", - rebase_path(dart_root_gen_dir), - "--package-name", - "snapshot_root", - "--depfile", - rebase_path(depfile), - "--deps", - ] + dart_deps + deps = [ + "//topaz/public/dart/fuchsia", + "//topaz/public/dart/zircon", + ] } } action("generate_snapshot_bin") { if (is_fuchsia) { snapshot_dart = "snapshot_fuchsia.dart" - # TODO(rmacnak): Fuchsia cross builds use the wrong Dart target # architecture, and have added steps that depend on this error for # reasonable build times (e.g., invoking the analyzer). @@ -105,9 +85,9 @@ action("generate_snapshot_bin") { rebased_dart_ui_path = rebase_path(dart_ui_path) - gen_snapshot_dir = get_label_info( - "//third_party/dart/runtime/bin:gen_snapshot($host_toolchain)", - "root_out_dir") + gen_snapshot_dir = + get_label_info("//third_party/dart/runtime/bin:gen_snapshot($host_toolchain)", + "root_out_dir") script = "//third_party/dart/runtime/tools/create_snapshot_bin.py" args = [ @@ -229,7 +209,7 @@ bin_to_assembly("isolate_snapshot_data_assembly") { ] input = "$target_gen_dir/isolate_snapshot.bin" output = "$target_gen_dir/isolate_snapshot_data.S" - symbol = "kDartIsolateSnapshotData" + symbol = "kDartIsolateCoreSnapshotData" executable = false } @@ -239,7 +219,7 @@ bin_to_assembly("isolate_snapshot_instructions_assembly") { ] input = "$target_gen_dir/isolate_snapshot_instructions.bin" output = "$target_gen_dir/isolate_snapshot_instructions.S" - symbol = "kDartIsolateSnapshotInstructions" + symbol = "kDartIsolateCoreSnapshotInstructions" executable = true } @@ -269,9 +249,9 @@ compile_platform("non_strong_platform") { ] args = [ - "--target=flutter", - "dart:core", - ] + "--target=flutter", + "dart:core", + ] } compile_platform("strong_platform") { @@ -285,10 +265,10 @@ compile_platform("strong_platform") { ] args = [ - "--target=flutter", - "--strong", - "dart:core", - ] + "--target=flutter", + "--strong", + "dart:core" + ] } group("kernel_platform_files") { diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 6a75cd22c8614..8b3be72d5973b 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -40,10 +40,14 @@ source_set("ui") { "painting/picture.h", "painting/picture_recorder.cc", "painting/picture_recorder.h", + "painting/resource_context.cc", + "painting/resource_context.h", "painting/rrect.cc", "painting/rrect.h", "painting/shader.cc", "painting/shader.h", + "painting/utils.cc", + "painting/utils.h", "painting/vertices.cc", "painting/vertices.h", "semantics/semantics_node.cc", @@ -83,18 +87,19 @@ source_set("ui") { "window/window.h", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] deps = [ + "//third_party/dart/runtime/bin:embedded_dart_io", "$flutter_root/assets", "$flutter_root/common", "$flutter_root/flow", - "$flutter_root/fml", "$flutter_root/glue", "$flutter_root/runtime:test_font", "$flutter_root/sky/engine", "$flutter_root/third_party/txt", - "//third_party/dart/runtime/bin:embedded_dart_io", "//third_party/rapidjson", "//third_party/skia", "//third_party/skia:gpu", diff --git a/lib/ui/compositing/scene_builder.cc b/lib/ui/compositing/scene_builder.cc index 60b911cb4ddec..006826abbfdf6 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -120,11 +120,10 @@ void SceneBuilder::addPicture(double dx, double dy, Picture* picture, int hints) { - layer_builder_->PushPicture( - SkPoint::Make(dx, dy), // - UIDartState::CreateGPUObject(picture->picture()), // - !!(hints & 1), // picture is complex - !!(hints & 2) // picture will change + layer_builder_->PushPicture(SkPoint::Make(dx, dy), // + picture->picture(), // + !!(hints & 1), // picture is complex + !!(hints & 2) // picture will change ); } diff --git a/lib/ui/compositing/scene_host.cc b/lib/ui/compositing/scene_host.cc index f5e0cfb3547d8..c0e4c5332580a 100644 --- a/lib/ui/compositing/scene_host.cc +++ b/lib/ui/compositing/scene_host.cc @@ -4,7 +4,6 @@ #include "flutter/lib/ui/compositing/scene_host.h" -#include "flutter/lib/ui/ui_dart_state.h" #include "lib/tonic/dart_args.h" #include "lib/tonic/dart_binding_macros.h" #include "lib/tonic/dart_library_natives.h" @@ -38,9 +37,8 @@ fxl::RefPtr SceneHost::create( } SceneHost::SceneHost(fxl::RefPtr export_token_handle) { - export_node_holder_ = fxl::MakeRefCounted( - blink::UIDartState::Current()->GetTaskRunners().GetGPUTaskRunner(), - export_token_handle); + export_node_holder_ = + fxl::MakeRefCounted(export_token_handle); } #else fxl::RefPtr SceneHost::create(Dart_Handle export_token_handle) { diff --git a/lib/ui/dart_runtime_hooks.cc b/lib/ui/dart_runtime_hooks.cc index 32a244c9cb67d..edd51245b05db 100644 --- a/lib/ui/dart_runtime_hooks.cc +++ b/lib/ui/dart_runtime_hooks.cc @@ -8,11 +8,7 @@ #include #include -#include -#include - #include "flutter/common/settings.h" -#include "flutter/lib/ui/ui_dart_state.h" #include "lib/fxl/build_config.h" #include "lib/fxl/logging.h" #include "lib/tonic/converter/dart_converter.h" @@ -145,43 +141,17 @@ void DartRuntimeHooks::Install(IsolateType isolate_type, // Implementation of native functions which are used for some // test/debug functionality in standalone dart mode. void Logger_PrintString(Dart_NativeArguments args) { - std::stringstream stream; - const auto& logger_prefix = UIDartState::Current()->logger_prefix(); - -#if !OS(ANDROID) - // Prepend all logs with the isolate debug name except on Android where that - // prefix is specified in the log tag. - if (logger_prefix.size() > 0) { - stream << logger_prefix << ": "; - } -#endif // !OS(ANDROID) - - // Append the log buffer obtained from Dart code. - { - Dart_Handle str = Dart_GetNativeArgument(args, 0); - uint8_t* chars = nullptr; - intptr_t length = 0; - Dart_Handle result = Dart_StringToUTF8(str, &chars, &length); - if (Dart_IsError(result)) { - Dart_PropagateError(result); - return; - } - if (length > 0) { - stream << std::string{reinterpret_cast(chars), - static_cast(length)}; - } - } - - const auto log_string = stream.str(); - const char* chars = log_string.c_str(); - const size_t length = log_string.size(); - - // Log using platform specific mechanisms - { + intptr_t length = 0; + uint8_t* chars = nullptr; + Dart_Handle str = Dart_GetNativeArgument(args, 0); + Dart_Handle result = Dart_StringToUTF8(str, &chars, &length); + if (Dart_IsError(result)) { + Dart_PropagateError(result); + } else { #if defined(OS_ANDROID) // Write to the logcat on Android. - __android_log_print(ANDROID_LOG_INFO, logger_prefix.c_str(), "%.*s", - (int)length, chars); + const char* tag = Settings::Get().log_tag.c_str(); + __android_log_print(ANDROID_LOG_INFO, tag, "%.*s", (int)length, chars); #elif defined(OS_IOS) // Write to syslog on iOS. // @@ -189,22 +159,26 @@ void Logger_PrintString(Dart_NativeArguments args) { // iOS logging APIs altogether. syslog(1 /* LOG_ALERT */, "%.*s", (int)length, chars); #else - std::cout << log_string << std::endl; + // On Fuchsia and in flutter_tester (on both macOS and Linux), write + // directly to stdout. + fwrite(chars, 1, length, stdout); + fputs("\n", stdout); + fflush(stdout); #endif } - if (dart::bin::ShouldCaptureStdout()) { // For now we report print output on the Stdout stream. uint8_t newline[] = {'\n'}; - Dart_ServiceSendDataEvent("Stdout", "WriteEvent", - reinterpret_cast(chars), length); + Dart_ServiceSendDataEvent("Stdout", "WriteEvent", chars, length); Dart_ServiceSendDataEvent("Stdout", "WriteEvent", newline, sizeof(newline)); } } void ScheduleMicrotask(Dart_NativeArguments args) { Dart_Handle closure = Dart_GetNativeArgument(args, 0); - UIDartState::Current()->ScheduleMicrotask(closure); + if (LogIfError(closure) || !Dart_IsClosure(closure)) + return; + tonic::DartMicrotaskQueue::GetForCurrentThread()->ScheduleMicrotask(closure); } } // namespace blink diff --git a/lib/ui/painting/codec.cc b/lib/ui/painting/codec.cc index 758a722b409e2..3e47ba86d50a5 100644 --- a/lib/ui/painting/codec.cc +++ b/lib/ui/painting/codec.cc @@ -4,11 +4,11 @@ #include "flutter/lib/ui/painting/codec.h" -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/glue/trace_event.h" #include "flutter/lib/ui/painting/frame_info.h" +#include "flutter/lib/ui/painting/resource_context.h" #include "lib/fxl/functional/make_copyable.h" -#include "lib/fxl/logging.h" #include "lib/tonic/dart_binding_macros.h" #include "lib/tonic/dart_library_natives.h" #include "lib/tonic/dart_state.h" @@ -17,10 +17,6 @@ #include "third_party/skia/include/codec/SkCodec.h" #include "third_party/skia/include/core/SkPixelRef.h" -#ifdef ERROR -#undef ERROR -#endif - using tonic::DartInvoke; using tonic::DartPersistentValue; using tonic::ToDart; @@ -32,9 +28,9 @@ namespace { static constexpr const char* kInitCodecTraceTag = "InitCodec"; static constexpr const char* kCodecNextFrameTraceTag = "CodecNextFrame"; -static void InvokeCodecCallback(fxl::RefPtr codec, - std::unique_ptr callback, - size_t trace_id) { +void InvokeCodecCallback(fxl::RefPtr codec, + std::unique_ptr callback, + size_t trace_id) { tonic::DartState* dart_state = callback->dart_state().get(); if (!dart_state) { TRACE_FLOW_END("flutter", kInitCodecTraceTag, trace_id); @@ -49,9 +45,7 @@ static void InvokeCodecCallback(fxl::RefPtr codec, TRACE_FLOW_END("flutter", kInitCodecTraceTag, trace_id); } -static sk_sp DecodeImage(fml::WeakPtr context, - sk_sp buffer, - size_t trace_id) { +sk_sp DecodeImage(sk_sp buffer, size_t trace_id) { TRACE_FLOW_STEP("flutter", kInitCodecTraceTag, trace_id); TRACE_EVENT0("flutter", "DecodeImage"); @@ -59,11 +53,13 @@ static sk_sp DecodeImage(fml::WeakPtr context, return nullptr; } + std::unique_ptr resourceContext = ResourceContext::Acquire(); + GrContext* context = resourceContext->Get(); if (context) { // This indicates that we do not want a "linear blending" decode. sk_sp dstColorSpace = nullptr; - return SkImage::MakeCrossContextFromEncoded( - context.get(), std::move(buffer), false, dstColorSpace.get()); + return SkImage::MakeCrossContextFromEncoded(context, std::move(buffer), + false, dstColorSpace.get()); } else { // Defer decoding until time of draw later on the GPU thread. Can happen // when GL operations are currently forbidden such as in the background @@ -72,10 +68,7 @@ static sk_sp DecodeImage(fml::WeakPtr context, } } -fxl::RefPtr InitCodec(fml::WeakPtr context, - sk_sp buffer, - fxl::RefPtr unref_queue, - size_t trace_id) { +fxl::RefPtr InitCodec(sk_sp buffer, size_t trace_id) { TRACE_FLOW_STEP("flutter", kInitCodecTraceTag, trace_id); TRACE_EVENT0("blink", "InitCodec"); @@ -93,31 +86,27 @@ fxl::RefPtr InitCodec(fml::WeakPtr context, if (skCodec->getFrameCount() > 1) { return fxl::MakeRefCounted(std::move(skCodec)); } - auto skImage = DecodeImage(context, buffer, trace_id); + auto skImage = DecodeImage(buffer, trace_id); if (!skImage) { FXL_LOG(ERROR) << "DecodeImage failed"; return nullptr; } auto image = CanvasImage::Create(); - image->set_image({skImage, unref_queue}); + image->set_image(skImage); auto frameInfo = fxl::MakeRefCounted(std::move(image), 0); return fxl::MakeRefCounted(std::move(frameInfo)); } void InitCodecAndInvokeCodecCallback( - fxl::RefPtr ui_task_runner, - fml::WeakPtr context, - fxl::RefPtr unref_queue, std::unique_ptr callback, sk_sp buffer, size_t trace_id) { - auto codec = - InitCodec(context, std::move(buffer), std::move(unref_queue), trace_id); - ui_task_runner->PostTask( - fxl::MakeCopyable([callback = std::move(callback), - codec = std::move(codec), trace_id]() mutable { - InvokeCodecCallback(std::move(codec), std::move(callback), trace_id); - })); + auto codec = InitCodec(std::move(buffer), trace_id); + Threads::UI()->PostTask(fxl::MakeCopyable([ + callback = std::move(callback), codec = std::move(codec), trace_id + ]() mutable { + InvokeCodecCallback(std::move(codec), std::move(callback), trace_id); + })); } void InstantiateImageCodec(Dart_NativeArguments args) { @@ -144,20 +133,14 @@ void InstantiateImageCodec(Dart_NativeArguments args) { auto buffer = SkData::MakeWithCopy(list.data(), list.num_elements()); - auto dart_state = UIDartState::Current(); - - const auto& task_runners = dart_state->GetTaskRunners(); - task_runners.GetIOTaskRunner()->PostTask(fxl::MakeCopyable( - [callback = std::make_unique( - tonic::DartState::Current(), callback_handle), - buffer = std::move(buffer), trace_id, - ui_task_runner = task_runners.GetUITaskRunner(), - context = dart_state->GetResourceContext(), - queue = UIDartState::Current()->GetSkiaUnrefQueue()]() mutable { - InitCodecAndInvokeCodecCallback(std::move(ui_task_runner), context, - std::move(queue), std::move(callback), - std::move(buffer), trace_id); - })); + Threads::IO()->PostTask(fxl::MakeCopyable([ + callback = std::make_unique( + tonic::DartState::Current(), callback_handle), + buffer = std::move(buffer), trace_id + ]() mutable { + InitCodecAndInvokeCodecCallback(std::move(callback), std::move(buffer), + trace_id); + })); } bool copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) { @@ -230,8 +213,7 @@ MultiFrameCodec::MultiFrameCodec(std::unique_ptr codec) nextFrameIndex_ = 0; } -sk_sp MultiFrameCodec::GetNextFrameImage( - fml::WeakPtr resourceContext) { +sk_sp MultiFrameCodec::GetNextFrameImage() { SkBitmap& bitmap = frameBitmaps_[nextFrameIndex_]; if (!bitmap.getPixels()) { // We haven't decoded this frame yet const SkImageInfo info = codec_->getInfo().makeColorType(kN32_SkColorType); @@ -263,13 +245,15 @@ sk_sp MultiFrameCodec::GetNextFrameImage( } } - if (resourceContext) { + std::unique_ptr resourceContext = ResourceContext::Acquire(); + GrContext* context = resourceContext->Get(); + if (context) { SkPixmap pixmap(bitmap.info(), bitmap.pixelRef()->pixels(), bitmap.pixelRef()->rowBytes()); // This indicates that we do not want a "linear blending" decode. sk_sp dstColorSpace = nullptr; - return SkImage::MakeCrossContextFromPixmap(resourceContext.get(), pixmap, - false, dstColorSpace.get()); + return SkImage::MakeCrossContextFromPixmap(context, pixmap, false, + dstColorSpace.get()); } else { // Defer decoding until time of draw later on the GPU thread. Can happen // when GL operations are currently forbidden such as in the background @@ -280,22 +264,19 @@ sk_sp MultiFrameCodec::GetNextFrameImage( void MultiFrameCodec::GetNextFrameAndInvokeCallback( std::unique_ptr callback, - fxl::RefPtr ui_task_runner, - fml::WeakPtr resourceContext, - fxl::RefPtr unref_queue, size_t trace_id) { fxl::RefPtr frameInfo = NULL; - sk_sp skImage = GetNextFrameImage(resourceContext); + sk_sp skImage = GetNextFrameImage(); if (skImage) { fxl::RefPtr image = CanvasImage::Create(); - image->set_image({skImage, std::move(unref_queue)}); + image->set_image(skImage); frameInfo = fxl::MakeRefCounted( std::move(image), frameInfos_[nextFrameIndex_].fDuration); } nextFrameIndex_ = (nextFrameIndex_ + 1) % frameInfos_.size(); - ui_task_runner->PostTask(fxl::MakeCopyable( - [callback = std::move(callback), frameInfo, trace_id]() mutable { + Threads::UI()->PostTask(fxl::MakeCopyable( + [ callback = std::move(callback), frameInfo, trace_id ]() mutable { InvokeNextFrameCallback(frameInfo, std::move(callback), trace_id); })); @@ -312,20 +293,13 @@ Dart_Handle MultiFrameCodec::getNextFrame(Dart_Handle callback_handle) { return ToDart("Callback must be a function"); } - auto dart_state = UIDartState::Current(); - - const auto& task_runners = dart_state->GetTaskRunners(); - - task_runners.GetIOTaskRunner()->PostTask(fxl::MakeCopyable( - [callback = std::make_unique( - tonic::DartState::Current(), callback_handle), - this, trace_id, ui_task_runner = task_runners.GetUITaskRunner(), - queue = UIDartState::Current()->GetSkiaUnrefQueue(), - context = dart_state->GetResourceContext()]() mutable { - GetNextFrameAndInvokeCallback(std::move(callback), - std::move(ui_task_runner), context, - std::move(queue), trace_id); - })); + Threads::IO()->PostTask(fxl::MakeCopyable([ + callback = std::make_unique( + tonic::DartState::Current(), callback_handle), + this, trace_id + ]() mutable { + GetNextFrameAndInvokeCallback(std::move(callback), trace_id); + })); return Dart_Null(); } diff --git a/lib/ui/painting/codec.h b/lib/ui/painting/codec.h index 9fdce1a8c1a33..98e5bc56df375 100644 --- a/lib/ui/painting/codec.h +++ b/lib/ui/painting/codec.h @@ -43,16 +43,11 @@ class MultiFrameCodec : public Codec { private: MultiFrameCodec(std::unique_ptr codec); - ~MultiFrameCodec() {} - sk_sp GetNextFrameImage(fml::WeakPtr resourceContext); - + sk_sp GetNextFrameImage(); void GetNextFrameAndInvokeCallback( std::unique_ptr callback, - fxl::RefPtr ui_task_runner, - fml::WeakPtr resourceContext, - fxl::RefPtr unref_queue, size_t trace_id); const std::unique_ptr codec_; diff --git a/lib/ui/painting/gradient.cc b/lib/ui/painting/gradient.cc index 52ccd63f3f5d3..f6bb864627740 100644 --- a/lib/ui/painting/gradient.cc +++ b/lib/ui/painting/gradient.cc @@ -48,10 +48,10 @@ void CanvasGradient::initLinear(const tonic::Float32List& end_points, static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor doesn't use int32_t."); - set_shader(UIDartState::CreateGPUObject(SkGradientShader::MakeLinear( + set_shader(SkGradientShader::MakeLinear( reinterpret_cast(end_points.data()), reinterpret_cast(colors.data()), color_stops.data(), - colors.num_elements(), tile_mode))); + colors.num_elements(), tile_mode)); } void CanvasGradient::initRadial(double center_x, @@ -73,14 +73,14 @@ void CanvasGradient::initRadial(double center_x, sk_matrix = ToSkMatrix(matrix4); } - set_shader(UIDartState::CreateGPUObject(SkGradientShader::MakeRadial( + set_shader(SkGradientShader::MakeRadial( SkPoint::Make(center_x, center_y), radius, reinterpret_cast(colors.data()), color_stops.data(), - colors.num_elements(), tile_mode, 0, has_matrix ? &sk_matrix : nullptr))); + colors.num_elements(), tile_mode, 0, has_matrix ? &sk_matrix : nullptr)); } -CanvasGradient::CanvasGradient() = default; +CanvasGradient::CanvasGradient() : Shader(nullptr) {} -CanvasGradient::~CanvasGradient() = default; +CanvasGradient::~CanvasGradient() {} } // namespace blink diff --git a/lib/ui/painting/image.cc b/lib/ui/painting/image.cc index a1b9b45cdc863..42e733241c990 100644 --- a/lib/ui/painting/image.cc +++ b/lib/ui/painting/image.cc @@ -4,7 +4,9 @@ #include "flutter/lib/ui/painting/image.h" +#include "flutter/common/threads.h" #include "flutter/lib/ui/painting/image_encoding.h" +#include "flutter/lib/ui/painting/utils.h" #include "lib/tonic/converter/dart_converter.h" #include "lib/tonic/dart_args.h" #include "lib/tonic/dart_binding_macros.h" @@ -28,9 +30,13 @@ void CanvasImage::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); } -CanvasImage::CanvasImage() = default; +CanvasImage::CanvasImage() {} -CanvasImage::~CanvasImage() = default; +CanvasImage::~CanvasImage() { + // Skia objects must be deleted on the IO thread so that any associated GL + // objects will be cleaned up through the IO thread's GL context. + SkiaUnrefOnIOThread(&image_); +} Dart_Handle CanvasImage::toByteData(int format, int quality, @@ -43,8 +49,8 @@ void CanvasImage::dispose() { } size_t CanvasImage::GetAllocationSize() { - if (auto image = image_.get()) { - return image->width() * image->height() * 4; + if (image_) { + return image_->width() * image_->height() * 4; } else { return sizeof(CanvasImage); } diff --git a/lib/ui/painting/image.h b/lib/ui/painting/image.h index aeec2a0149c73..a7ed4298506f5 100644 --- a/lib/ui/painting/image.h +++ b/lib/ui/painting/image.h @@ -5,8 +5,6 @@ #ifndef FLUTTER_LIB_UI_PAINTING_IMAGE_H_ #define FLUTTER_LIB_UI_PAINTING_IMAGE_H_ -#include "flutter/flow/skia_gpu_object.h" -#include "flutter/lib/ui/ui_dart_state.h" #include "lib/tonic/dart_wrappable.h" #include "third_party/skia/include/core/SkImage.h" @@ -27,18 +25,13 @@ class CanvasImage final : public fxl::RefCountedThreadSafe, return fxl::MakeRefCounted(); } - int width() { return image_.get()->width(); } - - int height() { return image_.get()->height(); } - + int width() { return image_->width(); } + int height() { return image_->height(); } Dart_Handle toByteData(int format, int quality, Dart_Handle callback); - void dispose(); - sk_sp image() const { return image_.get(); } - void set_image(flow::SkiaGPUObject image) { - image_ = std::move(image); - } + const sk_sp& image() const { return image_; } + void set_image(sk_sp image) { image_ = std::move(image); } virtual size_t GetAllocationSize() override; @@ -47,7 +40,7 @@ class CanvasImage final : public fxl::RefCountedThreadSafe, private: CanvasImage(); - flow::SkiaGPUObject image_; + sk_sp image_; }; } // namespace blink diff --git a/lib/ui/painting/image_encoding.cc b/lib/ui/painting/image_encoding.cc index f010fce893d3e..f356e955f6745 100644 --- a/lib/ui/painting/image_encoding.cc +++ b/lib/ui/painting/image_encoding.cc @@ -4,15 +4,13 @@ #include "flutter/lib/ui/painting/image_encoding.h" -#include -#include - -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/lib/ui/painting/image.h" -#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/painting/resource_context.h" #include "lib/fxl/build_config.h" #include "lib/fxl/functional/make_copyable.h" #include "lib/tonic/dart_persistent_value.h" +#include "lib/tonic/dart_state.h" #include "lib/tonic/logging/dart_invoke.h" #include "lib/tonic/typed_data/uint8_list.h" #include "third_party/skia/include/core/SkEncodedImageFormat.h" @@ -54,11 +52,10 @@ void EncodeImageAndInvokeDataCallback( std::unique_ptr callback, sk_sp image, SkEncodedImageFormat format, - int quality, - fxl::RefPtr ui_task_runner) { + int quality) { sk_sp encoded = EncodeImage(std::move(image), format, quality); - ui_task_runner->PostTask( + Threads::UI()->PostTask( fxl::MakeCopyable([callback = std::move(callback), encoded]() mutable { InvokeDataCallback(std::move(callback), std::move(encoded)); })); @@ -104,14 +101,10 @@ Dart_Handle EncodeImage(CanvasImage* canvas_image, tonic::DartState::Current(), callback_handle); sk_sp image = canvas_image->image(); - const auto& task_runners = UIDartState::Current()->GetTaskRunners(); - - task_runners.GetIOTaskRunner()->PostTask(fxl::MakeCopyable( - [callback = std::move(callback), image, image_format, quality, - ui_task_runner = task_runners.GetUITaskRunner()]() mutable { + Threads::IO()->PostTask(fxl::MakeCopyable( + [callback = std::move(callback), image, image_format, quality]() mutable { EncodeImageAndInvokeDataCallback(std::move(callback), std::move(image), - image_format, quality, - std::move(ui_task_runner)); + image_format, quality); })); return Dart_Null(); diff --git a/lib/ui/painting/image_shader.cc b/lib/ui/painting/image_shader.cc index a4ddbba0ea24b..0fabd134c737c 100644 --- a/lib/ui/painting/image_shader.cc +++ b/lib/ui/painting/image_shader.cc @@ -4,7 +4,6 @@ #include "flutter/lib/ui/painting/image_shader.h" -#include "flutter/lib/ui/ui_dart_state.h" #include "lib/tonic/converter/dart_converter.h" #include "lib/tonic/dart_args.h" #include "lib/tonic/dart_binding_macros.h" @@ -38,17 +37,15 @@ void ImageShader::initWithImage(CanvasImage* image, SkShader::TileMode tmx, SkShader::TileMode tmy, const tonic::Float64List& matrix4) { - if (!image) { + if (!image) Dart_ThrowException( ToDart("ImageShader constructor called with non-genuine Image.")); - } SkMatrix sk_matrix = ToSkMatrix(matrix4); - set_shader(UIDartState::CreateGPUObject( - image->image()->makeShader(tmx, tmy, &sk_matrix))); + set_shader(image->image()->makeShader(tmx, tmy, &sk_matrix)); } -ImageShader::ImageShader() = default; +ImageShader::ImageShader() : Shader(nullptr) {} -ImageShader::~ImageShader() = default; +ImageShader::~ImageShader() {} } // namespace blink diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 34f92b8c315fd..89ddbf5f41bb0 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -4,8 +4,9 @@ #include "flutter/lib/ui/painting/picture.h" +#include "flutter/common/threads.h" #include "flutter/lib/ui/painting/canvas.h" -#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/painting/utils.h" #include "lib/tonic/converter/dart_converter.h" #include "lib/tonic/dart_args.h" #include "lib/tonic/dart_binding_macros.h" @@ -22,20 +23,24 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Picture); DART_BIND_ALL(Picture, FOR_EACH_BINDING) -fxl::RefPtr Picture::Create(flow::SkiaGPUObject picture) { +fxl::RefPtr Picture::Create(sk_sp picture) { return fxl::MakeRefCounted(std::move(picture)); } -Picture::Picture(flow::SkiaGPUObject picture) - : picture_(std::move(picture)) {} +Picture::Picture(sk_sp picture) : picture_(std::move(picture)) {} -Picture::~Picture() = default; +Picture::~Picture() { + // Skia objects must be deleted on the IO thread so that any associated GL + // objects will be cleaned up through the IO thread's GL context. + SkiaUnrefOnIOThread(&picture_); +} fxl::RefPtr Picture::toImage(int width, int height) { fxl::RefPtr image = CanvasImage::Create(); - image->set_image(UIDartState::CreateGPUObject(SkImage::MakeFromPicture( - picture_.get(), SkISize::Make(width, height), nullptr, nullptr, - SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB()))); + // TODO(abarth): We should pass in an SkColorSpace at some point. + image->set_image(SkImage::MakeFromPicture( + picture_, SkISize::Make(width, height), nullptr, nullptr, + SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB())); return image; } @@ -44,8 +49,8 @@ void Picture::dispose() { } size_t Picture::GetAllocationSize() { - if (auto picture = picture_.get()) { - return picture->approximateBytesUsed(); + if (picture_) { + return picture_->approximateBytesUsed(); } else { return sizeof(Picture); } diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index d916086b02f02..4a26d01c08374 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -5,7 +5,6 @@ #ifndef FLUTTER_LIB_UI_PAINTING_PICTURE_H_ #define FLUTTER_LIB_UI_PAINTING_PICTURE_H_ -#include "flutter/flow/skia_gpu_object.h" #include "flutter/lib/ui/painting/image.h" #include "lib/tonic/dart_wrappable.h" #include "third_party/skia/include/core/SkPicture.h" @@ -24,9 +23,9 @@ class Picture : public fxl::RefCountedThreadSafe, public: ~Picture() override; - static fxl::RefPtr Create(flow::SkiaGPUObject picture); + static fxl::RefPtr Create(sk_sp picture); - sk_sp picture() const { return picture_.get(); } + const sk_sp& picture() const { return picture_; } fxl::RefPtr toImage(int width, int height); @@ -37,9 +36,9 @@ class Picture : public fxl::RefCountedThreadSafe, static void RegisterNatives(tonic::DartLibraryNatives* natives); private: - explicit Picture(flow::SkiaGPUObject picture); + explicit Picture(sk_sp picture); - flow::SkiaGPUObject picture_; + sk_sp picture_; }; } // namespace blink diff --git a/lib/ui/painting/picture_recorder.cc b/lib/ui/painting/picture_recorder.cc index e870e400a7230..adc73c0043920 100644 --- a/lib/ui/painting/picture_recorder.cc +++ b/lib/ui/painting/picture_recorder.cc @@ -50,9 +50,8 @@ SkCanvas* PictureRecorder::BeginRecording(SkRect bounds) { fxl::RefPtr PictureRecorder::endRecording() { if (!isRecording()) return nullptr; - - fxl::RefPtr picture = Picture::Create(UIDartState::CreateGPUObject( - picture_recorder_.finishRecordingAsPicture())); + fxl::RefPtr picture = + Picture::Create(picture_recorder_.finishRecordingAsPicture()); canvas_->Clear(); canvas_->ClearDartWrapper(); canvas_ = nullptr; diff --git a/lib/ui/painting/resource_context.cc b/lib/ui/painting/resource_context.cc new file mode 100644 index 0000000000000..1b9f71548c15f --- /dev/null +++ b/lib/ui/painting/resource_context.cc @@ -0,0 +1,51 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/lib/ui/painting/resource_context.h" + +#include + +#include "lib/fxl/logging.h" + +namespace blink { +namespace { + +static GrContext* g_context = nullptr; +static std::mutex g_mutex; +static volatile bool g_freeze = false; + +} // namespace + +ResourceContext::ResourceContext() { + g_mutex.lock(); +} + +ResourceContext::~ResourceContext() { + g_mutex.unlock(); +} + +void ResourceContext::Set(sk_sp context) { + FXL_DCHECK(!g_context); + g_context = context.release(); +} + +GrContext* ResourceContext::Get() { + return g_freeze ? nullptr : g_context; +} + +std::unique_ptr ResourceContext::Acquire() { + return std::make_unique(); +} + +void ResourceContext::Freeze() { + std::lock_guard lock(g_mutex); + g_freeze = true; +} + +void ResourceContext::Unfreeze() { + std::lock_guard lock(g_mutex); + g_freeze = false; +} + +} // namespace blink diff --git a/lib/ui/painting/resource_context.h b/lib/ui/painting/resource_context.h new file mode 100644 index 0000000000000..627b2053c2df9 --- /dev/null +++ b/lib/ui/painting/resource_context.h @@ -0,0 +1,60 @@ +// Copyright 2016 The Chromium 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_LIB_UI_PAINTING_RESOURCE_CONTEXT_H_ +#define FLUTTER_LIB_UI_PAINTING_RESOURCE_CONTEXT_H_ + +#include "lib/fxl/macros.h" +#include "third_party/skia/include/gpu/GrContext.h" + +namespace blink { + +class ResourceContext { + public: + /** + * Globally set the GrContext singleton instance. + */ + static void Set(sk_sp context); + + /** + * Acquire a GrContext wrapping ResourceContext that's also an exclusive mutex + * on GrContext operations. + * + * Destructing the ResourceContext frees the mutex. + */ + static std::unique_ptr Acquire(); + + /** + * Synchronously signal a freeze on GrContext operations. + * + * ResourceContext instances will return nullptr on GrContext Get until + * unfrozen. + */ + static void Freeze(); + + /** + * Synchronously unfreeze GrContext operations. + * + * ResourceContext instances will continue to return the global GrContext + * instance on Get. + */ + static void Unfreeze(); + + ResourceContext(); + ~ResourceContext(); + + /** + * Returns global GrContext instance. May return null when operations are + * frozen. + * + * Happens on iOS when background operations on GrContext are forbidden. + */ + GrContext* Get(); + + FXL_DISALLOW_COPY_AND_ASSIGN(ResourceContext); +}; + +} // namespace blink + +#endif // FLUTTER_LIB_UI_PAINTING_RESOURCE_CONTEXT_H_ diff --git a/lib/ui/painting/shader.cc b/lib/ui/painting/shader.cc index 7999b84dfcc29..d7d8ccf20aefc 100644 --- a/lib/ui/painting/shader.cc +++ b/lib/ui/painting/shader.cc @@ -4,15 +4,19 @@ #include "flutter/lib/ui/painting/shader.h" -#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/common/threads.h" +#include "flutter/lib/ui/painting/utils.h" namespace blink { IMPLEMENT_WRAPPERTYPEINFO(ui, Shader); -Shader::Shader(flow::SkiaGPUObject shader) - : shader_(std::move(shader)) {} +Shader::Shader(sk_sp shader) : shader_(shader) {} -Shader::~Shader() = default; +Shader::~Shader() { + // Skia objects must be deleted on the IO thread so that any associated GL + // objects will be cleaned up through the IO thread's GL context. + SkiaUnrefOnIOThread(&shader_); +} } // namespace blink diff --git a/lib/ui/painting/shader.h b/lib/ui/painting/shader.h index 205197250eb84..9c0f3c601db56 100644 --- a/lib/ui/painting/shader.h +++ b/lib/ui/painting/shader.h @@ -5,8 +5,6 @@ #ifndef FLUTTER_LIB_UI_PAINTING_SHADER_H_ #define FLUTTER_LIB_UI_PAINTING_SHADER_H_ -#include "flutter/flow/skia_gpu_object.h" -#include "flutter/lib/ui/ui_dart_state.h" #include "lib/tonic/dart_wrappable.h" #include "third_party/skia/include/core/SkShader.h" @@ -20,17 +18,14 @@ class Shader : public fxl::RefCountedThreadSafe, public: ~Shader() override; - sk_sp shader() { return shader_.get(); } - - void set_shader(flow::SkiaGPUObject shader) { - shader_ = std::move(shader); - } + const sk_sp& shader() { return shader_; } + void set_shader(sk_sp shader) { shader_ = std::move(shader); } protected: - Shader(flow::SkiaGPUObject shader = {}); + Shader(sk_sp shader); private: - flow::SkiaGPUObject shader_; + sk_sp shader_; }; } // namespace blink diff --git a/lib/ui/painting/utils.cc b/lib/ui/painting/utils.cc new file mode 100644 index 0000000000000..b3f87135ac0a8 --- /dev/null +++ b/lib/ui/painting/utils.cc @@ -0,0 +1,46 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/lib/ui/painting/utils.h" +#include "flutter/common/threads.h" + +namespace blink { + +namespace { + +constexpr fxl::TimeDelta kDrainDelay = fxl::TimeDelta::FromMilliseconds(250); + +} // anonymous namespace + +SkiaUnrefQueue::SkiaUnrefQueue() : drain_pending_(false) {} + +SkiaUnrefQueue SkiaUnrefQueue::instance_; + +SkiaUnrefQueue& SkiaUnrefQueue::Get() { + return instance_; +} + +void SkiaUnrefQueue::Unref(SkRefCnt* object) { + std::lock_guard lock(mutex_); + objects_.push_back(object); + if (!drain_pending_) { + drain_pending_ = true; + Threads::IO()->PostDelayedTask([this] { Drain(); }, kDrainDelay); + } +} + +void SkiaUnrefQueue::Drain() { + std::deque skia_objects; + { + std::lock_guard lock(mutex_); + objects_.swap(skia_objects); + drain_pending_ = false; + } + + for (SkRefCnt* skia_object : skia_objects) { + skia_object->unref(); + } +} + +} // namespace blink diff --git a/lib/ui/painting/utils.h b/lib/ui/painting/utils.h new file mode 100644 index 0000000000000..02782c67962bc --- /dev/null +++ b/lib/ui/painting/utils.h @@ -0,0 +1,38 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/skia/include/core/SkRefCnt.h" + +#include +#include + +namespace blink { + +// A queue that holds Skia objects that must be destructed on the IO thread. +class SkiaUnrefQueue { + public: + static SkiaUnrefQueue& Get(); + + void Unref(SkRefCnt* object); + + private: + SkiaUnrefQueue(); + void Drain(); + + static SkiaUnrefQueue instance_; + + std::mutex mutex_; + std::deque objects_; + bool drain_pending_; +}; + +template +void SkiaUnrefOnIOThread(sk_sp* sp) { + T* object = sp->release(); + if (object) { + SkiaUnrefQueue::Get().Unref(object); + } +} + +} // namespace blink diff --git a/lib/ui/text/font_collection.cc b/lib/ui/text/font_collection.cc index 248468cc9701d..d6407f9ed42e1 100644 --- a/lib/ui/text/font_collection.cc +++ b/lib/ui/text/font_collection.cc @@ -34,9 +34,15 @@ std::shared_ptr FontCollection::GetFontCollection() const { return collection_; } -void FontCollection::RegisterFonts(const AssetManager& asset_manager) { +void FontCollection::RegisterFontsFromAssetProvider( + fxl::RefPtr asset_provider) { + + if (!asset_provider){ + return; + } + std::vector manifest_data; - if (!asset_manager.GetAsBuffer("FontManifest.json", &manifest_data)) { + if (!asset_provider->GetAsBuffer("FontManifest.json", &manifest_data)) { FXL_DLOG(WARNING) << "Could not find the font manifest in the asset store."; return; } @@ -86,8 +92,8 @@ void FontCollection::RegisterFonts(const AssetManager& asset_manager) { // TODO: Handle weights and styles. std::vector font_data; - if (asset_manager.GetAsBuffer(font_asset->value.GetString(), - &font_data)) { + if (asset_provider->GetAsBuffer(font_asset->value.GetString(), + &font_data)) { // The data must be copied because it needs to be moved into the // typeface as a stream. auto data = diff --git a/lib/ui/text/font_collection.h b/lib/ui/text/font_collection.h index ea9c2f46a96a0..fb393b1582b79 100644 --- a/lib/ui/text/font_collection.h +++ b/lib/ui/text/font_collection.h @@ -7,10 +7,10 @@ #include #include - -#include "flutter/assets/asset_manager.h" +#include "flutter/assets/asset_provider.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_ptr.h" +#include "txt/asset_data_provider.h" #include "txt/font_collection.h" namespace blink { @@ -21,8 +21,7 @@ class FontCollection { std::shared_ptr GetFontCollection() const; - void RegisterFonts(const AssetManager& asset_manager); - + void RegisterFontsFromAssetProvider(fxl::RefPtr asset_provider); void RegisterTestFonts(); private: diff --git a/lib/ui/text/paragraph.cc b/lib/ui/text/paragraph.cc index fd00f6f51b3a3..858ccd01d4ef6 100644 --- a/lib/ui/text/paragraph.cc +++ b/lib/ui/text/paragraph.cc @@ -5,7 +5,7 @@ #include "flutter/lib/ui/text/paragraph.h" #include "flutter/common/settings.h" -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/sky/engine/core/rendering/PaintInfo.h" #include "flutter/sky/engine/core/rendering/RenderParagraph.h" #include "flutter/sky/engine/core/rendering/RenderText.h" @@ -53,8 +53,7 @@ Paragraph::Paragraph(std::unique_ptr paragraph) Paragraph::~Paragraph() { if (m_renderView) { RenderView* renderView = m_renderView.leakPtr(); - destruction_task_runner_->PostTask( - [renderView]() { renderView->destroy(); }); + Threads::UI()->PostTask([renderView]() { renderView->destroy(); }); } } diff --git a/lib/ui/text/paragraph.h b/lib/ui/text/paragraph.h index b3a943209ab4c..1b2019373553a 100644 --- a/lib/ui/text/paragraph.h +++ b/lib/ui/text/paragraph.h @@ -5,7 +5,6 @@ #ifndef FLUTTER_LIB_UI_TEXT_PARAGRAPH_H_ #define FLUTTER_LIB_UI_TEXT_PARAGRAPH_H_ -#include "flutter/fml/message_loop.h" #include "flutter/lib/ui/painting/canvas.h" #include "flutter/lib/ui/text/paragraph_impl.h" #include "flutter/lib/ui/text/paragraph_impl_blink.h" @@ -67,10 +66,6 @@ class Paragraph : public fxl::RefCountedThreadSafe, explicit Paragraph(std::unique_ptr paragraph); - // TODO: This can be removed when the render view association for the legacy - // runtime is removed. - fxl::RefPtr destruction_task_runner_ = - UIDartState::Current()->GetTaskRunners().GetUITaskRunner(); OwnPtr m_renderView; }; diff --git a/lib/ui/text/paragraph_builder.cc b/lib/ui/text/paragraph_builder.cc index b987e3fde6272..44d05053ba342 100644 --- a/lib/ui/text/paragraph_builder.cc +++ b/lib/ui/text/paragraph_builder.cc @@ -5,7 +5,7 @@ #include "flutter/lib/ui/text/paragraph_builder.h" #include "flutter/common/settings.h" -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/lib/ui/text/font_collection.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/sky/engine/core/rendering/RenderInline.h" @@ -205,11 +205,9 @@ fxl::RefPtr ParagraphBuilder::create( double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale, - bool use_blink) { - return fxl::MakeRefCounted( - encoded, fontFamily, fontSize, lineHeight, ellipsis, locale, - UIDartState::Current()->use_blink()); + const std::string& locale) { + return fxl::MakeRefCounted(encoded, fontFamily, fontSize, + lineHeight, ellipsis, locale); } ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, @@ -217,10 +215,8 @@ ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale, - bool use_blink) - : m_useBlink(use_blink) { - if (!m_useBlink) { + const std::string& locale) { + if (!Settings::Get().using_blink) { int32_t mask = encoded[0]; txt::ParagraphStyle style; if (mask & psTextAlignMask) @@ -279,8 +275,7 @@ ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, ParagraphBuilder::~ParagraphBuilder() { if (m_renderView) { RenderView* renderView = m_renderView.leakPtr(); - destruction_task_runner_->PostTask( - [renderView]() { renderView->destroy(); }); + Threads::UI()->PostTask([renderView]() { renderView->destroy(); }); } } @@ -295,7 +290,7 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, int32_t mask = encoded[0]; - if (!m_useBlink) { + if (!Settings::Get().using_blink) { // Set to use the properties of the previous style if the property is not // explicitly given. txt::TextStyle style = m_paragraphBuilder->PeekStyle(); @@ -428,7 +423,7 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, } void ParagraphBuilder::pop() { - if (!m_useBlink) { + if (!Settings::Get().using_blink) { m_paragraphBuilder->Pop(); } else { // Blink Version. @@ -450,7 +445,7 @@ Dart_Handle ParagraphBuilder::addText(const std::u16string& text) { if (error_code != U_BUFFER_OVERFLOW_ERROR) return tonic::ToDart("string is not well-formed UTF-16"); - if (!m_useBlink) { + if (!Settings::Get().using_blink) { m_paragraphBuilder->AddText(text); } else { // Blink Version. @@ -469,7 +464,7 @@ Dart_Handle ParagraphBuilder::addText(const std::u16string& text) { fxl::RefPtr ParagraphBuilder::build() { m_currentRenderObject = nullptr; - if (!m_useBlink) { + if (!Settings::Get().using_blink) { return Paragraph::Create(m_paragraphBuilder->Build()); } else { return Paragraph::Create(m_renderView.release()); diff --git a/lib/ui/text/paragraph_builder.h b/lib/ui/text/paragraph_builder.h index 1c38d98696def..37a1e9a3e74cf 100644 --- a/lib/ui/text/paragraph_builder.h +++ b/lib/ui/text/paragraph_builder.h @@ -32,8 +32,7 @@ class ParagraphBuilder : public fxl::RefCountedThreadSafe, double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale, - bool use_blink); + const std::string& locale); ~ParagraphBuilder() override; @@ -59,20 +58,14 @@ class ParagraphBuilder : public fxl::RefCountedThreadSafe, double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale, - bool use_blink); + const std::string& locale); void createRenderView(); - // TODO: This can be removed when the render view association for the legacy - // runtime is removed. - fxl::RefPtr destruction_task_runner_ = - UIDartState::Current()->GetTaskRunners().GetUITaskRunner(); OwnPtr m_renderView; RenderObject* m_renderParagraph; RenderObject* m_currentRenderObject; std::unique_ptr m_paragraphBuilder; - bool m_useBlink; }; } // namespace blink diff --git a/lib/ui/text/paragraph_impl_blink.cc b/lib/ui/text/paragraph_impl_blink.cc index 5c50f047afa33..c7752c0a7c757 100644 --- a/lib/ui/text/paragraph_impl_blink.cc +++ b/lib/ui/text/paragraph_impl_blink.cc @@ -4,6 +4,7 @@ #include "flutter/lib/ui/text/paragraph_impl_blink.h" +#include "flutter/common/threads.h" #include "flutter/lib/ui/text/paragraph.h" #include "flutter/lib/ui/text/paragraph_impl.h" #include "flutter/sky/engine/core/rendering/PaintInfo.h" @@ -29,8 +30,7 @@ ParagraphImplBlink::ParagraphImplBlink(PassOwnPtr renderView) ParagraphImplBlink::~ParagraphImplBlink() { if (m_renderView) { RenderView* renderView = m_renderView.leakPtr(); - destruction_task_runner_->PostTask( - [renderView]() { renderView->destroy(); }); + Threads::UI()->PostTask([renderView]() { renderView->destroy(); }); } } diff --git a/lib/ui/text/paragraph_impl_blink.h b/lib/ui/text/paragraph_impl_blink.h index ebd80f8dd5382..79d89ad471962 100644 --- a/lib/ui/text/paragraph_impl_blink.h +++ b/lib/ui/text/paragraph_impl_blink.h @@ -5,7 +5,6 @@ #ifndef FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_BLINK_H_ #define FLUTTER_LIB_UI_TEXT_PARAGRAPH_IMPL_BLINK_H_ -#include "flutter/fml/message_loop.h" #include "flutter/lib/ui/painting/canvas.h" #include "flutter/lib/ui/text/paragraph_impl.h" #include "flutter/lib/ui/text/text_box.h" @@ -42,10 +41,6 @@ class ParagraphImplBlink : public ParagraphImpl { int absoluteOffsetForPosition(const PositionWithAffinity& position); - // TODO: This can be removed when the render view association for the legacy - // runtime is removed. - fxl::RefPtr destruction_task_runner_ = - UIDartState::Current()->GetTaskRunners().GetUITaskRunner(); OwnPtr m_renderView; }; diff --git a/lib/ui/text/paragraph_impl_txt.cc b/lib/ui/text/paragraph_impl_txt.cc index 28c6ea19a8157..de8d8ff0b2fc3 100644 --- a/lib/ui/text/paragraph_impl_txt.cc +++ b/lib/ui/text/paragraph_impl_txt.cc @@ -4,7 +4,7 @@ #include "flutter/lib/ui/text/paragraph_impl_txt.h" -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/lib/ui/text/paragraph.h" #include "flutter/lib/ui/text/paragraph_impl.h" #include "lib/fxl/logging.h" diff --git a/lib/ui/ui_dart_state.cc b/lib/ui/ui_dart_state.cc index 8ef7ca98fd758..3bdf21e6a1a93 100644 --- a/lib/ui/ui_dart_state.cc +++ b/lib/ui/ui_dart_state.cc @@ -4,7 +4,6 @@ #include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/fml/message_loop.h" #include "flutter/lib/ui/window/window.h" #include "flutter/sky/engine/platform/fonts/FontSelector.h" #include "lib/tonic/converter/dart_converter.h" @@ -13,44 +12,34 @@ using tonic::ToDart; namespace blink { -UIDartState::UIDartState(TaskRunners task_runners, - TaskObserverAdd add_callback, - TaskObserverRemove remove_callback, - fml::WeakPtr resource_context, - fxl::RefPtr skia_unref_queue, - std::string advisory_script_uri, - std::string advisory_script_entrypoint, - std::string logger_prefix) - : task_runners_(std::move(task_runners)), - add_callback_(std::move(add_callback)), - remove_callback_(std::move(remove_callback)), - resource_context_(std::move(resource_context)), - advisory_script_uri_(std::move(advisory_script_uri)), - advisory_script_entrypoint_(std::move(advisory_script_entrypoint)), - logger_prefix_(std::move(logger_prefix)), - skia_unref_queue_(std::move(skia_unref_queue)), - weak_factory_(this) { - AddOrRemoveTaskObserver(true /* add */); -} +IsolateClient::~IsolateClient() {} -UIDartState::~UIDartState() { - AddOrRemoveTaskObserver(false /* remove */); -} +UIDartState::UIDartState(IsolateClient* isolate_client, + std::unique_ptr window, + int dirfd) + : tonic::DartState(dirfd), + isolate_client_(isolate_client), + main_port_(ILLEGAL_PORT), + window_(std::move(window)) {} -const std::string& UIDartState::GetAdvisoryScriptURI() const { - return advisory_script_uri_; +UIDartState::~UIDartState() { + main_port_ = ILLEGAL_PORT; + // We've already destroyed the isolate. Revoke any weak ptrs held by + // DartPersistentValues so they don't try to enter the destroyed isolate to + // clean themselves up. + // TODO(abarth): Can we do this work in the base class? + weak_factory_.InvalidateWeakPtrs(); } -const std::string& UIDartState::GetAdvisoryScriptEntrypoint() const { - return advisory_script_entrypoint_; +UIDartState* UIDartState::CreateForChildIsolate() { + return new UIDartState(isolate_client_, nullptr); } void UIDartState::DidSetIsolate() { + FXL_DCHECK(!debug_name_prefix_.empty()); main_port_ = Dart_GetMainPortId(); std::ostringstream debug_name; - // main.dart$main-1234 - debug_name << advisory_script_uri_ << "$" << advisory_script_entrypoint_ - << "-" << main_port_; + debug_name << debug_name_prefix_ << "$main-" << main_port_; debug_name_ = debug_name.str(); } @@ -66,48 +55,8 @@ PassRefPtr UIDartState::font_selector() { return font_selector_; } -void UIDartState::SetWindow(std::unique_ptr window) { - window_ = std::move(window); -} - -const TaskRunners& UIDartState::GetTaskRunners() const { - return task_runners_; -} - -fxl::RefPtr UIDartState::GetSkiaUnrefQueue() const { - return skia_unref_queue_; -} - -void UIDartState::ScheduleMicrotask(Dart_Handle closure) { - if (tonic::LogIfError(closure) || !Dart_IsClosure(closure)) { - return; - } - - microtask_queue_.ScheduleMicrotask(closure); -} - -void UIDartState::FlushMicrotasksNow() { - microtask_queue_.RunMicrotasks(); -} - -void UIDartState::AddOrRemoveTaskObserver(bool add) { - auto task_runner = task_runners_.GetUITaskRunner(); - if (!task_runner) { - // This may happen in case the isolate has no thread affinity (for example, - // the service isolate). - return; - } - FXL_DCHECK(add_callback_ && remove_callback_); - if (add) { - add_callback_(reinterpret_cast(this), - [this]() { this->FlushMicrotasksNow(); }); - } else { - remove_callback_(reinterpret_cast(this)); - } -} - -fml::WeakPtr UIDartState::GetResourceContext() const { - return resource_context_; +void UIDartState::set_debug_name_prefix(const std::string& debug_name_prefix) { + debug_name_prefix_ = debug_name_prefix; } } // namespace blink diff --git a/lib/ui/ui_dart_state.h b/lib/ui/ui_dart_state.h index a5c78c1671815..0f7f9343d4958 100644 --- a/lib/ui/ui_dart_state.h +++ b/lib/ui/ui_dart_state.h @@ -5,106 +5,65 @@ #ifndef FLUTTER_LIB_UI_UI_DART_STATE_H_ #define FLUTTER_LIB_UI_UI_DART_STATE_H_ -#include -#include #include -#include "flutter/common/settings.h" -#include "flutter/common/task_runners.h" -#include "flutter/flow/skia_gpu_object.h" -#include "flutter/fml/memory/weak_ptr.h" #include "flutter/sky/engine/wtf/RefPtr.h" #include "lib/fxl/build_config.h" -#include "lib/tonic/dart_microtask_queue.h" #include "lib/tonic/dart_persistent_value.h" #include "lib/tonic/dart_state.h" #include "third_party/dart/runtime/include/dart_api.h" -#include "third_party/skia/include/gpu/GrContext.h" namespace blink { class FontSelector; class Window; +class IsolateClient { + public: + virtual void DidCreateSecondaryIsolate(Dart_Isolate isolate) = 0; + virtual void DidShutdownMainIsolate() = 0; + + protected: + virtual ~IsolateClient(); +}; + class UIDartState : public tonic::DartState { public: + UIDartState(IsolateClient* isolate_client, + std::unique_ptr window, + int dirfd = -1); + ~UIDartState() override; + static UIDartState* Current(); - Dart_Port main_port() const { return main_port_; } + UIDartState* CreateForChildIsolate(); + IsolateClient* isolate_client() const { return isolate_client_; } + void set_isolate_client(IsolateClient* isolate_client) { + isolate_client_ = isolate_client; + } + Dart_Port main_port() const { return main_port_; } const std::string& debug_name() const { return debug_name_; } - - const std::string& logger_prefix() const { return logger_prefix_; } - Window* window() const { return window_.get(); } + void set_debug_name_prefix(const std::string& debug_name_prefix); void set_font_selector(PassRefPtr selector); - PassRefPtr font_selector(); - - bool use_blink() const { return use_blink_; } - - const TaskRunners& GetTaskRunners() const; - - void ScheduleMicrotask(Dart_Handle handle); - - void FlushMicrotasksNow(); - - fxl::RefPtr GetSkiaUnrefQueue() const; - - fml::WeakPtr GetResourceContext() const; - - template - static flow::SkiaGPUObject CreateGPUObject(sk_sp object) { - if (!object) { - return {}; - } - auto state = UIDartState::Current(); - FXL_DCHECK(state); - auto queue = state->GetSkiaUnrefQueue(); - return {std::move(object), std::move(queue)}; - }; - - protected: - UIDartState(TaskRunners task_runners, - TaskObserverAdd add_callback, - TaskObserverRemove remove_callback, - fml::WeakPtr resource_context, - fxl::RefPtr skia_unref_queue, - std::string advisory_script_uri, - std::string advisory_script_entrypoint, - std::string logger_prefix); - - ~UIDartState() override; - - void SetWindow(std::unique_ptr window); - - void set_use_blink(bool use_blink) { use_blink_ = use_blink; } - - const std::string& GetAdvisoryScriptURI() const; - - const std::string& GetAdvisoryScriptEntrypoint() const; + bool is_controller_state() const { return is_controller_state_; } + void set_is_controller_state(bool value) { is_controller_state_ = value; } + bool shutting_down() const { return shutting_down_; } + void set_shutting_down(bool value) { shutting_down_ = value; } private: void DidSetIsolate() override; - const TaskRunners task_runners_; - const TaskObserverAdd add_callback_; - const TaskObserverRemove remove_callback_; - fml::WeakPtr resource_context_; - const std::string advisory_script_uri_; - const std::string advisory_script_entrypoint_; - const std::string logger_prefix_; - Dart_Port main_port_ = ILLEGAL_PORT; + IsolateClient* isolate_client_; + Dart_Port main_port_; + std::string debug_name_prefix_; std::string debug_name_; std::unique_ptr window_; RefPtr font_selector_; - fxl::RefPtr skia_unref_queue_; - tonic::DartMicrotaskQueue microtask_queue_; - fml::WeakPtrFactory weak_factory_; - - void AddOrRemoveTaskObserver(bool add); - - bool use_blink_ = false; + bool is_controller_state_; + bool shutting_down_ = false; }; } // namespace blink diff --git a/lib/ui/window/platform_message_response_dart.cc b/lib/ui/window/platform_message_response_dart.cc index 2cca2fd179888..065159b79713b 100644 --- a/lib/ui/window/platform_message_response_dart.cc +++ b/lib/ui/window/platform_message_response_dart.cc @@ -6,7 +6,7 @@ #include -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/lib/ui/window/window.h" #include "lib/fxl/functional/make_copyable.h" #include "lib/tonic/dart_state.h" @@ -43,14 +43,12 @@ Dart_Handle WrapByteData(std::vector data) { } // anonymous namespace PlatformMessageResponseDart::PlatformMessageResponseDart( - tonic::DartPersistentValue callback, - fxl::RefPtr ui_task_runner) - : callback_(std::move(callback)), - ui_task_runner_(std::move(ui_task_runner)) {} + tonic::DartPersistentValue callback) + : callback_(std::move(callback)) {} PlatformMessageResponseDart::~PlatformMessageResponseDart() { if (!callback_.is_empty()) { - ui_task_runner_->PostTask( + Threads::UI()->PostTask( fxl::MakeCopyable([callback = std::move(callback_)]() mutable { callback.Clear(); })); @@ -62,7 +60,7 @@ void PlatformMessageResponseDart::Complete(std::vector data) { return; FXL_DCHECK(!is_complete_); is_complete_ = true; - ui_task_runner_->PostTask(fxl::MakeCopyable( + Threads::UI()->PostTask(fxl::MakeCopyable( [ callback = std::move(callback_), data = std::move(data) ]() mutable { tonic::DartState* dart_state = callback.dart_state().get(); if (!dart_state) @@ -79,7 +77,7 @@ void PlatformMessageResponseDart::CompleteEmpty() { return; FXL_DCHECK(!is_complete_); is_complete_ = true; - ui_task_runner_->PostTask( + Threads::UI()->PostTask( fxl::MakeCopyable([callback = std::move(callback_)]() mutable { tonic::DartState* dart_state = callback.dart_state().get(); if (!dart_state) diff --git a/lib/ui/window/platform_message_response_dart.h b/lib/ui/window/platform_message_response_dart.h index 67bfb3d359691..51c55a930014b 100644 --- a/lib/ui/window/platform_message_response_dart.h +++ b/lib/ui/window/platform_message_response_dart.h @@ -5,7 +5,6 @@ #ifndef FLUTTER_LIB_UI_PLATFORM_PLATFORM_MESSAGE_RESPONSE_DART_H_ #define FLUTTER_LIB_UI_PLATFORM_PLATFORM_MESSAGE_RESPONSE_DART_H_ -#include "flutter/fml/message_loop.h" #include "flutter/lib/ui/window/platform_message_response.h" #include "lib/tonic/dart_persistent_value.h" @@ -20,13 +19,10 @@ class PlatformMessageResponseDart : public PlatformMessageResponse { void CompleteEmpty() override; protected: - explicit PlatformMessageResponseDart( - tonic::DartPersistentValue callback, - fxl::RefPtr ui_task_runner); + explicit PlatformMessageResponseDart(tonic::DartPersistentValue callback); ~PlatformMessageResponseDart() override; tonic::DartPersistentValue callback_; - fxl::RefPtr ui_task_runner_; }; } // namespace blink diff --git a/lib/ui/window/viewport_metrics.h b/lib/ui/window/viewport_metrics.h index 5085d06f42724..1e443ae8c1404 100644 --- a/lib/ui/window/viewport_metrics.h +++ b/lib/ui/window/viewport_metrics.h @@ -23,25 +23,6 @@ struct ViewportMetrics { int32_t physical_view_inset_left = 0; }; -struct LogicalSize { - double width = 0.0; - double height = 0.0; -}; - -struct LogicalInset { - double left = 0.0; - double top = 0.0; - double right = 0.0; - double bottom = 0.0; -}; - -struct LogicalMetrics { - LogicalSize size; - double scale = 1.0; - LogicalInset padding; - LogicalInset view_inset; -}; - } // namespace blink #endif // FLUTTER_LIB_UI_WINDOW_VIEWPORT_METRICS_H_ diff --git a/lib/ui/window/window.cc b/lib/ui/window/window.cc index 4cce1cc5903b0..e12e03f10d01f 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -63,8 +63,7 @@ void SendPlatformMessage(Dart_Handle window, fxl::RefPtr response; if (!Dart_IsNull(callback)) { response = fxl::MakeRefCounted( - tonic::DartPersistentValue(dart_state, callback), - dart_state->GetTaskRunners().GetUITaskRunner()); + tonic::DartPersistentValue(dart_state, callback)); } if (Dart_IsNull(data.dart_handle())) { UIDartState::Current()->window()->client()->HandlePlatformMessage( @@ -255,7 +254,7 @@ void Window::BeginFrame(fxl::TimePoint frameTime) { Dart_NewInteger(microseconds), }); - UIDartState::Current()->FlushMicrotasksNow(); + tonic::DartMicrotaskQueue::GetForCurrentThread()->RunMicrotasks(); DartInvokeField(library_.value(), "_drawFrame", {}); } diff --git a/lib/ui/window/window.h b/lib/ui/window/window.h index 2feeccb65f9cc..ef0d7ef863a0e 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -13,7 +13,6 @@ #include "flutter/lib/ui/window/viewport_metrics.h" #include "lib/fxl/time/time_point.h" #include "lib/tonic/dart_persistent_value.h" -#include "third_party/skia/include/gpu/GrContext.h" namespace tonic { class DartLibraryNatives; @@ -36,14 +35,12 @@ class WindowClient { virtual ~WindowClient(); }; -class Window final { +class Window { public: explicit Window(WindowClient* client); - ~Window(); WindowClient* client() const { return client_; } - const ViewportMetrics& viewport_metrics() { return viewport_metrics_; } void DidCreateIsolate(); diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 455d7e228168f..dea8a8906d031 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -4,7 +4,6 @@ import("//third_party/dart/runtime/bin/vmservice/vmservice_sources.gni") import("$flutter_root/common/config.gni") -import("$flutter_root/testing/testing.gni") action("gen_embedded_resources_cc") { script = "//third_party/dart/runtime/tools/create_resources.py" @@ -38,7 +37,9 @@ source_set("embedded_resources_cc") { deps = [ ":gen_embedded_resources_cc", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] } source_set("test_font") { @@ -49,7 +50,9 @@ source_set("test_font") { deps = [ "//third_party/skia", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] defines = [] if (flutter_runtime_mode == "debug" || current_toolchain == host_toolchain) { # Though the test font data is small, we dont want to add to the binary size @@ -60,19 +63,16 @@ source_set("test_font") { } source_set("runtime") { + sources = [ "asset_font_selector.cc", "asset_font_selector.h", - "dart_isolate.cc", - "dart_isolate.h", + "dart_controller.cc", + "dart_controller.h", + "dart_init.cc", + "dart_init.h", "dart_service_isolate.cc", "dart_service_isolate.h", - "dart_snapshot.cc", - "dart_snapshot.h", - "dart_snapshot_buffer.cc", - "dart_snapshot_buffer.h", - "dart_vm.cc", - "dart_vm.h", "embedder_resources.cc", "embedder_resources.h", "platform_impl.cc", @@ -81,8 +81,8 @@ source_set("runtime") { "runtime_controller.h", "runtime_delegate.cc", "runtime_delegate.h", - "service_protocol.cc", - "service_protocol.h", + "runtime_init.cc", + "runtime_init.h", "start_up.cc", "start_up.h", "test_font_selector.cc", @@ -92,24 +92,25 @@ source_set("runtime") { deps = [ ":embedded_resources_cc", ":test_font", + "//third_party/dart/runtime:dart_api", + "//third_party/dart/runtime/bin:embedded_dart_io", "$flutter_root/assets", "$flutter_root/common", "$flutter_root/flow", - "$flutter_root/fml", "$flutter_root/glue", "$flutter_root/lib/io", "$flutter_root/lib/ui", "$flutter_root/sky/engine/platform", "$flutter_root/third_party/txt", "//garnet/public/lib/fxl", - "//third_party/dart/runtime:dart_api", - "//third_party/dart/runtime/bin:embedded_dart_io", "//third_party/rapidjson", "//third_party/skia", "//topaz/lib/tonic", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] # In AOT mode, precompiled snapshots contain the instruction buffer. # Generation of the same requires all application specific script code to be @@ -118,28 +119,3 @@ source_set("runtime") { deps += [ "$flutter_root/lib/snapshot" ] } } - -test_fixtures("runtime_fixtures") { - fixtures = [ "fixtures/simple_main.dart" ] -} - -executable("runtime_unittests") { - testonly = true - - sources = [ - "dart_isolate_unittests.cc", - "dart_vm_unittests.cc", - ] - - deps = [ - ":runtime", - ":runtime_fixtures", - "$flutter_root/fml", - "$flutter_root/lib/snapshot", - "$flutter_root/testing", - "//garnet/public/lib/fxl", - "//third_party/dart/runtime:libdart_jit", - "//third_party/skia", - "//topaz/lib/tonic", - ] -} diff --git a/runtime/asset_font_selector.cc b/runtime/asset_font_selector.cc index 2a43f39e3a89b..abf4bf9874ddd 100644 --- a/runtime/asset_font_selector.cc +++ b/runtime/asset_font_selector.cc @@ -80,15 +80,27 @@ struct FontMatcher { } // namespace -void AssetFontSelector::Install(fxl::RefPtr asset_manager) { +void AssetFontSelector::Install( + fxl::RefPtr asset_provider) { RefPtr font_selector = - adoptRef(new AssetFontSelector(std::move(asset_manager))); + adoptRef(new AssetFontSelector(std::move(asset_provider))); font_selector->parseFontManifest(); UIDartState::Current()->set_font_selector(font_selector); } -AssetFontSelector::AssetFontSelector(fxl::RefPtr asset_manager) - : asset_manager_(std::move(asset_manager)) {} +void AssetFontSelector::Install(fxl::RefPtr asset_store) { + RefPtr font_selector = + adoptRef(new AssetFontSelector(std::move(asset_store))); + font_selector->parseFontManifest(); + UIDartState::Current()->set_font_selector(font_selector); +} + +AssetFontSelector::AssetFontSelector( + fxl::RefPtr asset_provider) + : asset_provider_(std::move(asset_provider)) {} + +AssetFontSelector::AssetFontSelector(fxl::RefPtr asset_store) + : asset_store_(std::move(asset_store)) {} AssetFontSelector::~AssetFontSelector() {} @@ -106,9 +118,12 @@ AssetFontSelector::FlutterFontAttributes::~FlutterFontAttributes() {} void AssetFontSelector::parseFontManifest() { std::vector font_manifest_data; - if (!asset_manager_->GetAsBuffer(kFontManifestAssetPath, - &font_manifest_data)) { - return; + if (!asset_provider_ || + !asset_provider_->GetAsBuffer(kFontManifestAssetPath, + &font_manifest_data)) { + if (!asset_store_ || + !asset_store_->GetAsBuffer(kFontManifestAssetPath, &font_manifest_data)) + return; } rapidjson::Document document; @@ -224,8 +239,13 @@ sk_sp AssetFontSelector::getTypefaceAsset( } std::unique_ptr typeface_asset(new TypefaceAsset); - if (!asset_manager_->GetAsBuffer(asset_path, &typeface_asset->data)) { - return nullptr; + if (!asset_provider_ || !asset_provider_->GetAsBuffer( + asset_path, &typeface_asset->data)) { + if (!asset_store_ || + !asset_store_->GetAsBuffer(asset_path, &typeface_asset->data)) { + typeface_cache_.insert(std::make_pair(asset_path, nullptr)); + return nullptr; + } } sk_sp font_mgr(SkFontMgr::RefDefault()); diff --git a/runtime/asset_font_selector.h b/runtime/asset_font_selector.h index 8d7e946d89e7e..921c0472dba78 100644 --- a/runtime/asset_font_selector.h +++ b/runtime/asset_font_selector.h @@ -8,7 +8,7 @@ #include #include -#include "flutter/assets/asset_manager.h" +#include "flutter/assets/directory_asset_bundle.h" #include "flutter/assets/zip_asset_store.h" #include "flutter/sky/engine/platform/fonts/FontCacheKey.h" #include "flutter/sky/engine/platform/fonts/FontSelector.h" @@ -24,7 +24,11 @@ class AssetFontSelector : public FontSelector { ~AssetFontSelector() override; - static void Install(fxl::RefPtr asset_manager); + static void Install(fxl::RefPtr asset_provider); + + // TODO(zarah): Remove this and related code using asset_store once flx is + // removed. + static void Install(fxl::RefPtr asset_store); PassRefPtr getFontData(const FontDescription& font_description, const AtomicString& family_name) override; @@ -40,14 +44,19 @@ class AssetFontSelector : public FontSelector { private: struct TypefaceAsset; - explicit AssetFontSelector(fxl::RefPtr asset_manager); + explicit AssetFontSelector( + fxl::RefPtr asset_provider); + + explicit AssetFontSelector(fxl::RefPtr asset_store); void parseFontManifest(); sk_sp getTypefaceAsset(const FontDescription& font_description, const AtomicString& family_name); - fxl::RefPtr asset_manager_; + fxl::RefPtr asset_provider_; + + fxl::RefPtr asset_store_; HashMap> font_family_map_; diff --git a/runtime/dart_controller.cc b/runtime/dart_controller.cc new file mode 100644 index 0000000000000..84cfceeaecc10 --- /dev/null +++ b/runtime/dart_controller.cc @@ -0,0 +1,250 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/runtime/dart_controller.h" +#include "lib/fxl/build_config.h" + +#if defined(OS_WIN) +#include +#undef GetCurrentDirectory +#endif + +#include + +#include "flutter/common/settings.h" +#include "flutter/common/threads.h" +#include "flutter/glue/trace_event.h" +#include "flutter/lib/io/dart_io.h" +#include "flutter/lib/ui/dart_runtime_hooks.h" +#include "flutter/lib/ui/dart_ui.h" +#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/runtime/dart_init.h" +#include "flutter/runtime/dart_service_isolate.h" +#include "lib/fxl/files/directory.h" +#include "lib/fxl/files/path.h" +#include "lib/tonic/dart_class_library.h" +#include "lib/tonic/dart_message_handler.h" +#include "lib/tonic/dart_state.h" +#include "lib/tonic/dart_wrappable.h" +#include "lib/tonic/file_loader/file_loader.h" +#include "lib/tonic/logging/dart_error.h" +#include "lib/tonic/logging/dart_invoke.h" +#include "lib/tonic/scopes/dart_api_scope.h" +#include "lib/tonic/scopes/dart_isolate_scope.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +using tonic::LogIfError; +using tonic::ToDart; + +namespace blink { +namespace { +#if defined(OS_WIN) + +std::string FindAndReplace(const std::string& str, + const std::string& findStr, + const std::string& replaceStr) { + std::string rStr = str; + size_t pos = 0; + while ((pos = rStr.find(findStr, pos)) != std::string::npos) { + rStr.replace(pos, findStr.length(), replaceStr); + pos += replaceStr.length(); + } + return rStr; +} + +std::string SanitizePath(const std::string& path) { + return FindAndReplace(path, "\\\\", "/"); +} + +std::string ResolvePath(std::string path) { + std::string sanitized = SanitizePath(path); + if ((sanitized.length() > 2) && (sanitized[1] == ':')) { + return sanitized; + } + return files::SimplifyPath(files::GetCurrentDirectory() + "/" + sanitized); +} + +#else // defined(OS_WIN) + +std::string SanitizePath(const std::string& path) { + return path; +} + +// TODO(abarth): Consider adding this to //garnet/public/lib/fxl. +std::string ResolvePath(std::string path) { + if (!path.empty() && path[0] == '/') + return path; + return files::SimplifyPath(files::GetCurrentDirectory() + "/" + path); +} + +#endif + +} // namespace + +DartController::DartController() : ui_dart_state_(nullptr) {} + +DartController::~DartController() { + if (ui_dart_state_) { + ui_dart_state_->set_isolate_client(nullptr); + + if (!ui_dart_state_->shutting_down()) { + // Don't use a tonic::DartIsolateScope here since we never exit the + // isolate. + Dart_EnterIsolate(ui_dart_state_->isolate()); + // Clear the message notify callback. + Dart_SetMessageNotifyCallback(nullptr); + Dart_ShutdownIsolate(); + } + } +} + +const std::string DartController::main_entrypoint_ = "main"; + +bool DartController::SendStartMessage(Dart_Handle root_library, + const std::string& entrypoint) { + if (LogIfError(root_library)) + return true; + + { + // Temporarily exit the isolate while we make it runnable. + Dart_Isolate isolate = dart_state()->isolate(); + FXL_DCHECK(Dart_CurrentIsolate() == isolate); + Dart_ExitIsolate(); + Dart_IsolateMakeRunnable(isolate); + Dart_EnterIsolate(isolate); + } + + // In order to support pausing the isolate at start, we indirectly invoke + // main by sending a message to the isolate. + + // Get the closure of main(). + Dart_Handle main_closure = Dart_GetClosure( + root_library, Dart_NewStringFromCString(entrypoint.c_str())); + if (LogIfError(main_closure)) + return true; + + // Grab the 'dart:isolate' library. + Dart_Handle isolate_lib = Dart_LookupLibrary(ToDart("dart:isolate")); + DART_CHECK_VALID(isolate_lib); + + // Send the start message containing the entry point by calling + // _startMainIsolate in dart:isolate. + const intptr_t kNumIsolateArgs = 2; + Dart_Handle isolate_args[kNumIsolateArgs]; + isolate_args[0] = main_closure; + isolate_args[1] = Dart_Null(); + Dart_Handle result = Dart_Invoke(isolate_lib, ToDart("_startMainIsolate"), + kNumIsolateArgs, isolate_args); + return LogIfError(result); +} + +tonic::DartErrorHandleType DartController::RunFromKernel( + const std::vector& kernel, + const std::string& entrypoint) { + tonic::DartState::Scope scope(dart_state()); + tonic::DartErrorHandleType error = tonic::kNoError; + if (Dart_IsNull(Dart_RootLibrary())) { + Dart_Handle result = Dart_LoadScriptFromKernel(kernel.data(), kernel.size()); + LogIfError(result); + error = tonic::GetErrorHandleType(result); + } + if (SendStartMessage(Dart_RootLibrary(), entrypoint)) { + return tonic::kUnknownErrorType; + } + return error; +} + +tonic::DartErrorHandleType DartController::RunFromPrecompiledSnapshot( + const std::string& entrypoint) { + TRACE_EVENT0("flutter", "DartController::RunFromPrecompiledSnapshot"); + FXL_DCHECK(Dart_CurrentIsolate() == nullptr); + tonic::DartState::Scope scope(dart_state()); + if (SendStartMessage(Dart_RootLibrary(), entrypoint)) { + return tonic::kUnknownErrorType; + } + return tonic::kNoError; +} + +tonic::DartErrorHandleType DartController::RunFromScriptSnapshot( + const uint8_t* buffer, + size_t size, + const std::string& entrypoint) { + tonic::DartState::Scope scope(dart_state()); + tonic::DartErrorHandleType error = tonic::kNoError; + if (Dart_IsNull(Dart_RootLibrary())) { + Dart_Handle result = Dart_LoadScriptFromSnapshot(buffer, size); + LogIfError(result); + error = tonic::GetErrorHandleType(result); + } + if (SendStartMessage(Dart_RootLibrary(), entrypoint)) { + return tonic::kUnknownErrorType; + } + return error; +} + +tonic::DartErrorHandleType DartController::RunFromSource( + const std::string& main, + const std::string& packages) { + tonic::DartState::Scope scope(dart_state()); + tonic::DartErrorHandleType error = tonic::kNoError; + if (Dart_IsNull(Dart_RootLibrary())) { + tonic::FileLoader& loader = dart_state()->file_loader(); + if (!packages.empty() && !loader.LoadPackagesMap(ResolvePath(packages))) + FXL_LOG(WARNING) << "Failed to load package map: " << packages; + Dart_Handle result = loader.LoadScript(SanitizePath(main)); + LogIfError(result); + error = tonic::GetErrorHandleType(result); + } + if (SendStartMessage(Dart_RootLibrary())) { + return tonic::kCompilationErrorType; + } + return error; +} + +void DartController::CreateIsolateFor(const std::string& script_uri, + const uint8_t* isolate_snapshot_data, + const uint8_t* isolate_snapshot_instr, + std::unique_ptr state) { + char* error = nullptr; + + void* platform_kernel = GetKernelPlatformBinary(); + + Dart_Isolate isolate; + if (platform_kernel != nullptr) { + isolate = Dart_CreateIsolateFromKernel( + script_uri.c_str(), "main", platform_kernel, nullptr /* flags */, + static_cast(state.get()), &error); + } else { + isolate = + Dart_CreateIsolate(script_uri.c_str(), "main", isolate_snapshot_data, + isolate_snapshot_instr, nullptr, + static_cast(state.get()), &error); + } + FXL_CHECK(isolate) << error; + ui_dart_state_ = state.release(); + ui_dart_state_->set_is_controller_state(true); + dart_state()->message_handler().Initialize(blink::Threads::UI()); + + Dart_SetShouldPauseOnStart(Settings::Get().start_paused); + + ui_dart_state_->set_debug_name_prefix(script_uri); + ui_dart_state_->SetIsolate(isolate); + FXL_CHECK(!LogIfError( + Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))); + + { + tonic::DartApiScope dart_api_scope; + DartIO::InitForIsolate(); + DartUI::InitForIsolate(); + DartRuntimeHooks::Install(DartRuntimeHooks::MainIsolate, script_uri); + + std::unique_ptr ui_class_provider( + new tonic::DartClassProvider(dart_state(), "dart:ui")); + dart_state()->class_library().add_provider("ui", + std::move(ui_class_provider)); + } + Dart_ExitIsolate(); +} + +} // namespace blink diff --git a/runtime/dart_controller.h b/runtime/dart_controller.h new file mode 100644 index 0000000000000..4b11a8660b7e7 --- /dev/null +++ b/runtime/dart_controller.h @@ -0,0 +1,55 @@ +// Copyright 2015 The Chromium 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_RUNTIME_DART_CONTROLLER_H_ +#define FLUTTER_RUNTIME_DART_CONTROLLER_H_ + +#include +#include + +#include "lib/fxl/macros.h" +#include "lib/tonic/logging/dart_error.h" +#include "third_party/dart/runtime/include/dart_api.h" + +namespace blink { +class UIDartState; + +class DartController { + public: + DartController(); + ~DartController(); + + tonic::DartErrorHandleType RunFromKernel( + const std::vector& kernel, + const std::string& entrypoint = main_entrypoint_); + tonic::DartErrorHandleType RunFromPrecompiledSnapshot( + const std::string& entrypoint = main_entrypoint_); + tonic::DartErrorHandleType RunFromScriptSnapshot( + const uint8_t* buffer, + size_t size, + const std::string& entrypoint = main_entrypoint_); + tonic::DartErrorHandleType RunFromSource(const std::string& main, + const std::string& packages); + + void CreateIsolateFor(const std::string& script_uri, + const uint8_t* isolate_snapshot_data, + const uint8_t* isolate_snapshot_instr, + std::unique_ptr ui_dart_state); + + UIDartState* dart_state() const { return ui_dart_state_; } + + private: + bool SendStartMessage(Dart_Handle root_library, + const std::string& entrypoint = main_entrypoint_); + + static const std::string main_entrypoint_; + + // The DartState associated with the main isolate. + UIDartState* ui_dart_state_; + + FXL_DISALLOW_COPY_AND_ASSIGN(DartController); +}; +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_CONTROLLER_H_ diff --git a/runtime/dart_init.cc b/runtime/dart_init.cc new file mode 100644 index 0000000000000..e3d88322a4882 --- /dev/null +++ b/runtime/dart_init.cc @@ -0,0 +1,725 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/runtime/dart_init.h" +#include "flutter/sky/engine/wtf/OperatingSystem.h" + +#include +#include +#include + +#if defined(OS_WIN) +#include +#include +#undef ERROR + +#define access _access +#define R_OK 0x4 + +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#endif + +#else +#include +#endif + +#include +#include +#include +#include + +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/assets/unzipper_provider.h" +#include "flutter/assets/zip_asset_store.h" +#include "flutter/common/settings.h" +#include "flutter/glue/trace_event.h" +#include "flutter/lib/io/dart_io.h" +#include "flutter/lib/ui/dart_runtime_hooks.h" +#include "flutter/lib/ui/dart_ui.h" +#include "flutter/lib/ui/ui_dart_state.h" +#include "flutter/lib/ui/window/window.h" +#include "flutter/runtime/dart_service_isolate.h" +#include "flutter/runtime/start_up.h" +#include "lib/fxl/arraysize.h" +#include "lib/fxl/build_config.h" +#include "lib/fxl/files/path.h" +#include "lib/fxl/files/file.h" +#include "lib/fxl/logging.h" +#include "lib/fxl/time/time_delta.h" +#include "lib/tonic/converter/dart_converter.h" +#include "lib/tonic/dart_class_library.h" +#include "lib/tonic/dart_state.h" +#include "lib/tonic/dart_sticky_error.h" +#include "lib/tonic/dart_wrappable.h" +#include "lib/tonic/file_loader/file_loader.h" +#include "lib/tonic/logging/dart_error.h" +#include "lib/tonic/logging/dart_invoke.h" +#include "lib/tonic/scopes/dart_api_scope.h" +#include "lib/tonic/scopes/dart_isolate_scope.h" +#include "lib/tonic/typed_data/uint8_list.h" +#include "third_party/dart/runtime/bin/embedded_dart_io.h" +#include "third_party/dart/runtime/include/dart_mirrors_api.h" + +using tonic::DartClassProvider; +using tonic::LogIfError; +using tonic::ToDart; + +namespace dart { +namespace observatory { + +#if !OS(FUCHSIA) && FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE + +// These two symbols are defined in |observatory_archive.cc| which is generated +// by the |//third_party/dart/runtime/observatory:archive_observatory| rule. +// Both of these symbols will be part of the data segment and therefore are read +// only. +extern unsigned int observatory_assets_archive_len; +extern const uint8_t* observatory_assets_archive; + +#endif // FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE + +} // namespace observatory +} // namespace dart + +namespace blink { + +const char kKernelAssetKey[] = "kernel_blob.bin"; +const char kSnapshotAssetKey[] = "snapshot_blob.bin"; +const char kPlatformKernelAssetKey[] = "platform.dill"; + +namespace { + +// Arguments passed to the Dart VM in all configurations. +static const char* kDartLanguageArgs[] = { + "--enable_mirrors=false", "--background_compilation", "--await_is_keyword", + "--causal_async_stacks", "--limit-ints-to-64-bits", +}; + +static const char* kDartPrecompilationArgs[] = { + "--precompilation", +}; + +static const char* kDartWriteProtectCodeArgs[] FXL_ALLOW_UNUSED_TYPE = { + "--no_write_protect_code", +}; + +static const char* kDartAssertArgs[] = { + // clang-format off + "--enable_asserts", + // clang-format on +}; + +static const char* kDartCheckedModeArgs[] = { + // clang-format off + "--enable_type_checks", + "--error_on_bad_type", + "--error_on_bad_override", + // clang-format on +}; + +static const char* kDartStrongModeArgs[] = { + // clang-format off + "--limit_ints_to_64_bits", + "--reify_generic_functions", + "--strong", + "--sync_async", + // clang-format on +}; + +static const char* kDartStartPausedArgs[]{ + "--pause_isolates_on_start", +}; + +static const char* kDartTraceStartupArgs[]{ + "--timeline_streams=Compiler,Dart,Embedder,GC", +}; + +static const char* kDartEndlessTraceBufferArgs[]{ + "--timeline_recorder=endless", +}; + +static const char* kDartFuchsiaTraceArgs[] FXL_ALLOW_UNUSED_TYPE = { + "--systrace_timeline", + "--timeline_streams=VM,Isolate,Compiler,Dart,GC", +}; + +constexpr char kFileUriPrefix[] = "file://"; +constexpr size_t kFileUriPrefixLength = sizeof(kFileUriPrefix) - 1; + +static const uint8_t* g_default_isolate_snapshot_data = nullptr; +static const uint8_t* g_default_isolate_snapshot_instructions = nullptr; +static bool g_service_isolate_initialized = false; +static ServiceIsolateHook g_service_isolate_hook = nullptr; +static RegisterNativeServiceProtocolExtensionHook + g_register_native_service_protocol_extensions_hook = nullptr; + +// Kernel representation of core dart libraries(loaded from platform.dill). +// TODO(aam): This (and platform_data below) have to be released when engine +// gets torn down. At that point we could also call Dart_Cleanup to complete +// Dart VM cleanup. +static void* kernel_platform = nullptr; +// Bytes actually read from platform.dill that are referenced by kernel_platform +static std::vector platform_data; + +void IsolateShutdownCallback(void* callback_data) { + if (tonic::DartStickyError::IsSet()) { + tonic::DartApiScope api_scope; + FXL_LOG(ERROR) << "Isolate " << tonic::StdStringFromDart(Dart_DebugName()) + << " exited with an error"; + Dart_Handle sticky_error = Dart_GetStickyError(); + FXL_CHECK(LogIfError(sticky_error)); + } + + UIDartState* dart_state = static_cast(callback_data); + // If the isolate that's shutting down is the main one, tell the higher layers + // of the stack. + if ((dart_state != NULL) && dart_state->is_controller_state()) { + dart_state->set_shutting_down(true); + if (dart_state->isolate_client()) { + dart_state->isolate_client()->DidShutdownMainIsolate(); + } + } +} + +// The cleanup callback frees the DartState object. +void IsolateCleanupCallback(void* callback_data) { + UIDartState* dart_state = static_cast(callback_data); + delete dart_state; +} + +bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) { + if (strncmp(source_url, kFileUriPrefix, kFileUriPrefixLength) != 0u) { + // Assume modified. + return true; + } + + const char* path = source_url + kFileUriPrefixLength; + struct stat info; + if (stat(path, &info) < 0) + return true; + + // If st_mtime is zero, it's more likely that the file system doesn't support + // mtime than that the file was actually modified in the 1970s. + if (!info.st_mtime) + return true; + + // It's very unclear what time bases we're with here. The Dart API doesn't + // document the time base for since_ms. Reading the code, the value varies by + // platform, with a typical source being something like gettimeofday. + // + // We add one to st_mtime because st_mtime has less precision than since_ms + // and we want to treat the file as modified if the since time is between + // ticks of the mtime. + fxl::TimeDelta mtime = fxl::TimeDelta::FromSeconds(info.st_mtime + 1); + fxl::TimeDelta since = fxl::TimeDelta::FromMilliseconds(since_ms); + + return mtime > since; +} + +void ThreadExitCallback() {} + +bool IsServiceIsolateURL(const char* url_name) { + return url_name != nullptr && + std::string(url_name) == DART_VM_SERVICE_ISOLATE_NAME; +} + +static bool StringEndsWith(const std::string& string, + const std::string& ending) { + if (ending.size() > string.size()) + return false; + + return string.compare(string.size() - ending.size(), ending.size(), ending) == + 0; +} + +static void ReleaseFetchedBytes(uint8_t* buffer) { + free(buffer); +} + +Dart_Isolate ServiceIsolateCreateCallback(const char* script_uri, + Dart_IsolateFlags* flags, + char** error) { +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE + // No VM-service in release mode. + return nullptr; +#else // FLUTTER_RUNTIME_MODE + UIDartState* dart_state = new UIDartState(nullptr, nullptr); + + bool is_running_from_kernel = GetKernelPlatformBinary() != nullptr; + + flags->load_vmservice_library = true; + Dart_Isolate isolate = + is_running_from_kernel + ? Dart_CreateIsolateFromKernel( + script_uri, "main", kernel_platform, flags, + static_cast(dart_state), error) + : Dart_CreateIsolate( + script_uri, "main", g_default_isolate_snapshot_data, + g_default_isolate_snapshot_instructions, flags, + static_cast(dart_state), error); + + FXL_CHECK(isolate) << error; + dart_state->set_debug_name_prefix(script_uri); + dart_state->SetIsolate(isolate); + FXL_CHECK(Dart_IsServiceIsolate(isolate)); + FXL_CHECK(!LogIfError( + Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))); + { + tonic::DartApiScope dart_api_scope; + DartIO::InitForIsolate(); + DartUI::InitForIsolate(); + DartRuntimeHooks::Install(DartRuntimeHooks::SecondaryIsolate, script_uri); + const Settings& settings = Settings::Get(); + if (settings.enable_observatory) { + std::string ip = settings.ipv6 ? "::1" : "127.0.0.1"; + const intptr_t port = settings.observatory_port; + const bool disable_websocket_origin_check = false; + const bool service_isolate_booted = DartServiceIsolate::Startup( + ip, port, tonic::DartState::HandleLibraryTag, + !IsRunningPrecompiledCode() && !is_running_from_kernel, + disable_websocket_origin_check, error); + FXL_CHECK(service_isolate_booted) << error; + } + + if (g_service_isolate_hook) + g_service_isolate_hook(IsRunningPrecompiledCode()); + } + Dart_ExitIsolate(); + + g_service_isolate_initialized = true; + // Register any native service protocol extensions. + if (g_register_native_service_protocol_extensions_hook) { + g_register_native_service_protocol_extensions_hook( + IsRunningPrecompiledCode()); + } + return isolate; +#endif // FLUTTER_RUNTIME_MODE +} + +static bool GetAssetAsBuffer( + const std::string& name, + std::vector* data, + fxl::RefPtr& directory_asset_bundle, + fxl::RefPtr& asset_store) { + return (directory_asset_bundle && + directory_asset_bundle->GetAsBuffer(name, data)) || + (asset_store && asset_store->GetAsBuffer(name, data)); +} + +Dart_Isolate IsolateCreateCallback(const char* script_uri, + const char* main, + const char* package_root, + const char* package_config, + Dart_IsolateFlags* flags, + void* callback_data, + char** error) { + TRACE_EVENT0("flutter", __func__); + + if (IsServiceIsolateURL(script_uri)) { + return ServiceIsolateCreateCallback(script_uri, flags, error); + } + + std::string entry_uri = script_uri; + // Are we running from a Dart source file? + const bool running_from_source = StringEndsWith(entry_uri, ".dart"); + + std::vector kernel_data; + std::vector snapshot_data; + std::string entry_path; + if (!IsRunningPrecompiledCode()) { + // Check that the entry script URI starts with file:// + if (entry_uri.find(kFileUriPrefix) != 0u) { + *error = strdup("Isolates must use file:// URIs"); + return nullptr; + } + // Entry script path (file:// is stripped). + entry_path = std::string(script_uri + strlen(kFileUriPrefix)); + if (StringEndsWith(entry_path, ".dill")) { + // Load the kernel from the script URI. + if (!files::ReadFileToVector(entry_path, &kernel_data)) { + FXL_LOG(ERROR) << "Failed to load kernel"; + } + } else if (!running_from_source) { + // Attempt to copy the snapshot or kernel from the asset bundle. + const std::string& bundle_path = entry_path; + + struct stat stat_result = {}; + if (::stat(bundle_path.c_str(), &stat_result) == 0) { + fxl::RefPtr directory_asset_bundle; + // TODO(zarah): Remove usage of zip_asset_store once app.flx is removed. + fxl::RefPtr zip_asset_store; + // bundle_path is either the path to app.flx or the flutter assets + // directory. + std::string flx_path = bundle_path; + if (S_ISDIR(stat_result.st_mode)) { + directory_asset_bundle = + fxl::MakeRefCounted(bundle_path); + flx_path = files::GetDirectoryName(bundle_path) + "/app.flx"; + } + + if (access(flx_path.c_str(), R_OK) == 0) { + zip_asset_store = fxl::MakeRefCounted( + GetUnzipperProviderForPath(flx_path)); + } + GetAssetAsBuffer(kKernelAssetKey, &kernel_data, directory_asset_bundle, + zip_asset_store); + GetAssetAsBuffer(kSnapshotAssetKey, &snapshot_data, + directory_asset_bundle, zip_asset_store); + } + } + } + + UIDartState* parent_dart_state = static_cast(callback_data); + UIDartState* dart_state = parent_dart_state->CreateForChildIsolate(); + + Dart_Isolate isolate = + kernel_platform != nullptr + ? Dart_CreateIsolateFromKernel(script_uri, main, kernel_platform, + nullptr /* flags */, dart_state, error) + : Dart_CreateIsolate(script_uri, main, + g_default_isolate_snapshot_data, + g_default_isolate_snapshot_instructions, nullptr, + dart_state, error); + FXL_CHECK(isolate) << error; + dart_state->set_debug_name_prefix(script_uri); + dart_state->SetIsolate(isolate); + FXL_CHECK(!LogIfError( + Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))); + + { + tonic::DartApiScope dart_api_scope; + DartIO::InitForIsolate(); + DartUI::InitForIsolate(); + DartRuntimeHooks::Install(DartRuntimeHooks::SecondaryIsolate, script_uri); + + std::unique_ptr ui_class_provider( + new DartClassProvider(dart_state, "dart:ui")); + dart_state->class_library().add_provider("ui", + std::move(ui_class_provider)); + + if (!kernel_data.empty()) { + // We are running kernel code. + FXL_CHECK(!LogIfError(Dart_LoadScriptFromKernel(kernel_data.data(), + kernel_data.size()))); + } else if (!snapshot_data.empty()) { + // We are running from a script snapshot. + FXL_CHECK(!LogIfError(Dart_LoadScriptFromSnapshot(snapshot_data.data(), + snapshot_data.size()))); + } else if (running_from_source) { + // We are running from source. + // Forward the .packages configuration from the parent isolate to the + // child isolate. + tonic::FileLoader& parent_loader = parent_dart_state->file_loader(); + const std::string& packages = parent_loader.packages(); + tonic::FileLoader& loader = dart_state->file_loader(); + if (!packages.empty() && !loader.LoadPackagesMap(packages)) { + FXL_LOG(WARNING) << "Failed to load package map: " << packages; + } + // Load the script. + FXL_CHECK(!LogIfError(loader.LoadScript(entry_path))); + } + + dart_state->isolate_client()->DidCreateSecondaryIsolate(isolate); + } + + Dart_ExitIsolate(); + + FXL_CHECK(Dart_IsolateMakeRunnable(isolate)); + return isolate; +} + +Dart_Handle GetVMServiceAssetsArchiveCallback() { +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE + return nullptr; +#elif OS(FUCHSIA) + std::vector observatory_assets_archive; + if (!files::ReadFileToVector("pkg/data/observatory.tar", + &observatory_assets_archive)) { + FXL_LOG(ERROR) << "Fail to load Observatory archive"; + return nullptr; + } + return tonic::DartConverter::ToDart( + observatory_assets_archive.data(), + observatory_assets_archive.size()); +#else + return tonic::DartConverter::ToDart( + ::dart::observatory::observatory_assets_archive, + ::dart::observatory::observatory_assets_archive_len); +#endif +} + +static const char kStdoutStreamId[] = "Stdout"; +static const char kStderrStreamId[] = "Stderr"; + +static bool ServiceStreamListenCallback(const char* stream_id) { + if (strcmp(stream_id, kStdoutStreamId) == 0) { + dart::bin::SetCaptureStdout(true); + return true; + } else if (strcmp(stream_id, kStderrStreamId) == 0) { + dart::bin::SetCaptureStderr(true); + return true; + } + return false; +} + +static void ServiceStreamCancelCallback(const char* stream_id) { + if (strcmp(stream_id, kStdoutStreamId) == 0) { + dart::bin::SetCaptureStdout(false); + } else if (strcmp(stream_id, kStderrStreamId) == 0) { + dart::bin::SetCaptureStderr(false); + } +} + +} // namespace + +bool IsRunningPrecompiledCode() { + return Dart_IsPrecompiledRuntime(); +} + +EmbedderTracingCallbacks* g_tracing_callbacks = nullptr; + +EmbedderTracingCallbacks::EmbedderTracingCallbacks( + EmbedderTracingCallback start, + EmbedderTracingCallback stop) + : start_tracing_callback(start), stop_tracing_callback(stop) {} + +void SetEmbedderTracingCallbacks( + std::unique_ptr callbacks) { + g_tracing_callbacks = callbacks.release(); +} + +static void EmbedderTimelineStartRecording() { + if (g_tracing_callbacks) + g_tracing_callbacks->start_tracing_callback(); +} + +static void EmbedderTimelineStopRecording() { + if (g_tracing_callbacks) + g_tracing_callbacks->stop_tracing_callback(); +} + +static std::vector ProfilingFlags(bool enable_profiling) { +// Disable Dart's built in profiler when building a debug build. This +// works around a race condition that would sometimes stop a crash's +// stack trace from being printed on Android. +#ifndef NDEBUG + enable_profiling = false; +#endif + + // We want to disable profiling by default because it overwhelms LLDB. But + // the VM enables the same by default. In either case, we have some profiling + // flags. + if (enable_profiling) { + return { + // This is the default. But just be explicit. + "--profiler", + // This instructs the profiler to walk C++ frames, and to include + // them in the profile. + "--profile-vm"}; + } else { + return {"--no-profiler"}; + } +} + +void SetServiceIsolateHook(ServiceIsolateHook hook) { + FXL_CHECK(!g_service_isolate_initialized); + g_service_isolate_hook = hook; +} + +void SetRegisterNativeServiceProtocolExtensionHook( + RegisterNativeServiceProtocolExtensionHook hook) { + FXL_CHECK(!g_service_isolate_initialized); + g_register_native_service_protocol_extensions_hook = hook; +} + +void PushBackAll(std::vector* args, + const char** argv, + size_t argc) { + for (size_t i = 0; i < argc; ++i) { + args->push_back(argv[i]); + } +} + +static void EmbedderInformationCallback(Dart_EmbedderInformation* info) { + info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION; + dart::bin::GetIOEmbedderInformation(info); + info->name = "Flutter"; +} + +void* GetKernelPlatformBinary() { + return kernel_platform; +} + +void InitDartVM(const uint8_t* vm_snapshot_data, + const uint8_t* vm_snapshot_instructions, + const uint8_t* default_isolate_snapshot_data, + const uint8_t* default_isolate_snapshot_instructions, + const std::string& bundle_path) { + TRACE_EVENT0("flutter", __func__); + + g_default_isolate_snapshot_data = default_isolate_snapshot_data; + g_default_isolate_snapshot_instructions = + default_isolate_snapshot_instructions; + + const Settings& settings = Settings::Get(); + + { + TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo"); + dart::bin::BootstrapDartIo(); + + if (!settings.temp_directory_path.empty()) { + dart::bin::SetSystemTempDirectory(settings.temp_directory_path.c_str()); + } + } + + std::vector args; + + // Instruct the VM to ignore unrecognized flags. + // There is a lot of diversity in a lot of combinations when it + // comes to the arguments the VM supports. And, if the VM comes across a flag + // it does not recognize, it exits immediately. + args.push_back("--ignore-unrecognized-flags"); + + for (const auto& profiler_flag : + ProfilingFlags(settings.enable_dart_profiling)) { + args.push_back(profiler_flag); + } + + PushBackAll(&args, kDartLanguageArgs, arraysize(kDartLanguageArgs)); + + if (IsRunningPrecompiledCode()) { + PushBackAll(&args, kDartPrecompilationArgs, + arraysize(kDartPrecompilationArgs)); + } + +#if defined(OS_FUCHSIA) +#if defined(NDEBUG) + // Do not enable checked mode for Fuchsia release builds + // TODO(mikejurka): remove this once precompiled code is working on Fuchsia + const bool use_checked_mode = false; +#else // !defined(NDEBUG) + const bool use_checked_mode = true; +#endif // !defined(NDEBUG) +#else // !defined(OS_FUCHSIA) + // Enable checked mode if we are not running precompiled code. We run non- + // precompiled code only in the debug product mode. + const bool use_checked_mode = + !IsRunningPrecompiledCode() && !settings.dart_non_checked_mode; +#endif // !defined(OS_FUCHSIA) + +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG + // Debug mode uses the JIT, disable code page write protection to avoid + // memory page protection changes before and after every compilation. + PushBackAll(&args, kDartWriteProtectCodeArgs, + arraysize(kDartWriteProtectCodeArgs)); +#endif + + if (settings.start_paused) + PushBackAll(&args, kDartStartPausedArgs, arraysize(kDartStartPausedArgs)); + + if (settings.endless_trace_buffer || settings.trace_startup) { + // If we are tracing startup, make sure the trace buffer is endless so we + // don't lose early traces. + PushBackAll(&args, kDartEndlessTraceBufferArgs, + arraysize(kDartEndlessTraceBufferArgs)); + } + + if (settings.trace_startup) { + PushBackAll(&args, kDartTraceStartupArgs, arraysize(kDartTraceStartupArgs)); + } + +#if defined(OS_FUCHSIA) + PushBackAll(&args, kDartFuchsiaTraceArgs, arraysize(kDartFuchsiaTraceArgs)); +#endif + + if (!bundle_path.empty()) { + fxl::RefPtr directory_asset_bundle = + fxl::MakeRefCounted( + std::move(bundle_path)); + directory_asset_bundle->GetAsBuffer(kPlatformKernelAssetKey, + &platform_data); + if (!platform_data.empty()) { + uint8_t* kernel_buf = static_cast(malloc(platform_data.size())); + memcpy(kernel_buf, platform_data.data(), platform_data.size()); + kernel_platform = Dart_ReadKernelBinary(kernel_buf, platform_data.size(), + ReleaseFetchedBytes); + FXL_DCHECK(kernel_platform != nullptr); + } + } + if ((kernel_platform != nullptr) || + Dart_IsDart2Snapshot(g_default_isolate_snapshot_data)) { + // The presence of the kernel platform file or a snapshot that was generated + // for Dart2 indicates we are running in preview-dart-2 mode and in this + // mode enable strong mode options by default. + // Note: When we start using core snapshots instead of the platform file + // in the engine just sniffing the snapshot file should be sufficient. + PushBackAll(&args, kDartStrongModeArgs, arraysize(kDartStrongModeArgs)); + // In addition if we are running in debug mode we also enable asserts. + if (use_checked_mode) { + PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); + } + } else if (use_checked_mode) { + // In non preview-dart-2 mode we enable checked mode and asserts if + // we are running in debug mode. + PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); + PushBackAll(&args, kDartCheckedModeArgs, arraysize(kDartCheckedModeArgs)); + } + + for (size_t i = 0; i < settings.dart_flags.size(); i++) + args.push_back(settings.dart_flags[i].c_str()); + + FXL_CHECK(Dart_SetVMFlags(args.size(), args.data())); + + DartUI::InitForGlobal(); + + // Setup embedder tracing hooks. To avoid data races, it is recommended that + // these hooks be installed before the DartInitialize, so do that setup now. + Dart_SetEmbedderTimelineCallbacks(&EmbedderTimelineStartRecording, + &EmbedderTimelineStopRecording); + + Dart_SetFileModifiedCallback(&DartFileModifiedCallback); + + { + TRACE_EVENT0("flutter", "Dart_Initialize"); + Dart_InitializeParams params = {}; + params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; + params.vm_snapshot_data = vm_snapshot_data; + params.vm_snapshot_instructions = vm_snapshot_instructions; + params.create = IsolateCreateCallback; + params.shutdown = IsolateShutdownCallback; + params.cleanup = IsolateCleanupCallback; + params.thread_exit = ThreadExitCallback; + params.get_service_assets = GetVMServiceAssetsArchiveCallback; + params.entropy_source = DartIO::EntropySource; + char* init_error = Dart_Initialize(¶ms); + if (init_error != nullptr) + FXL_LOG(FATAL) << "Error while initializing the Dart VM: " << init_error; + free(init_error); + + // Send the earliest available timestamp in the application lifecycle to + // timeline. The difference between this timestamp and the time we render + // the very first frame gives us a good idea about Flutter's startup time. + // Use a duration event so about:tracing will consider this event when + // deciding the earliest event to use as time 0. + if (blink::engine_main_enter_ts != 0) { + Dart_TimelineEvent("FlutterEngineMainEnter", // label + blink::engine_main_enter_ts, // timestamp0 + blink::engine_main_enter_ts, // timestamp1_or_async_id + Dart_Timeline_Event_Duration, // event type + 0, // argument_count + nullptr, // argument_names + nullptr // argument_values + ); + } + } + + // Allow streaming of stdout and stderr by the Dart vm. + Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback, + &ServiceStreamCancelCallback); + + Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback); +} + +} // namespace blink diff --git a/runtime/dart_init.h b/runtime/dart_init.h new file mode 100644 index 0000000000000..99c8fe89137e3 --- /dev/null +++ b/runtime/dart_init.h @@ -0,0 +1,64 @@ +// Copyright 2015 The Chromium 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_RUNTIME_DART_INIT_H_ +#define FLUTTER_RUNTIME_DART_INIT_H_ + +#include "lib/fxl/build_config.h" +#include "lib/fxl/functional/closure.h" +#include "third_party/dart/runtime/include/dart_api.h" + +#include +#include +#include + +namespace blink { + +// Name of the kernel blob asset within the asset directory. +extern const char kKernelAssetKey[]; + +// Name of the snapshot blob asset within the asset directory. +extern const char kSnapshotAssetKey[]; + +// Name of the platform kernel blob asset within the asset directory. +extern const char kPlatformKernelAssetKey[]; + +bool IsRunningPrecompiledCode(); + +using EmbedderTracingCallback = fxl::Closure; + +typedef void (*ServiceIsolateHook)(bool); +typedef void (*RegisterNativeServiceProtocolExtensionHook)(bool); + +struct EmbedderTracingCallbacks { + EmbedderTracingCallback start_tracing_callback; + EmbedderTracingCallback stop_tracing_callback; + + EmbedderTracingCallbacks(EmbedderTracingCallback start, + EmbedderTracingCallback stop); +}; + +void InitDartVM(const uint8_t* vm_snapshot_data, + const uint8_t* vm_snapshot_instructions, + const uint8_t* default_isolate_snapshot_data, + const uint8_t* default_isolate_snapshot_instructions, + const std::string& bundle_path); + +void* GetKernelPlatformBinary(); + +void SetEmbedderTracingCallbacks( + std::unique_ptr callbacks); + +// Provide a function that will be called during initialization of the +// service isolate. +void SetServiceIsolateHook(ServiceIsolateHook hook); + +// Provide a function that will be called to register native service protocol +// extensions. +void SetRegisterNativeServiceProtocolExtensionHook( + RegisterNativeServiceProtocolExtensionHook hook); + +} // namespace blink + +#endif // FLUTTER_RUNTIME_DART_INIT_H_ diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc deleted file mode 100644 index c5fd770b1b40c..0000000000000 --- a/runtime/dart_isolate.cc +++ /dev/null @@ -1,715 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/runtime/dart_isolate.h" - -#include -#include - -#include "flutter/fml/trace_event.h" -#include "flutter/lib/io/dart_io.h" -#include "flutter/lib/ui/dart_runtime_hooks.h" -#include "flutter/lib/ui/dart_ui.h" -#include "flutter/runtime/dart_service_isolate.h" -#include "flutter/runtime/dart_vm.h" -#include "lib/fxl/files/path.h" -#include "lib/tonic/converter/dart_converter.h" -#include "lib/tonic/dart_class_library.h" -#include "lib/tonic/dart_class_provider.h" -#include "lib/tonic/dart_message_handler.h" -#include "lib/tonic/dart_state.h" -#include "lib/tonic/dart_sticky_error.h" -#include "lib/tonic/file_loader/file_loader.h" -#include "lib/tonic/scopes/dart_api_scope.h" -#include "lib/tonic/scopes/dart_isolate_scope.h" -#include "third_party/dart/runtime/include/dart_tools_api.h" - -#ifdef ERROR -#undef ERROR -#endif - -namespace blink { - -fml::WeakPtr DartIsolate::CreateRootIsolate( - const DartVM* vm, - fxl::RefPtr isolate_snapshot, - TaskRunners task_runners, - std::unique_ptr window, - fml::WeakPtr resource_context, - fxl::RefPtr unref_queue, - std::string advisory_script_uri, - std::string advisory_script_entrypoint, - Dart_IsolateFlags* flags) { - TRACE_EVENT0("flutter", "DartIsolate::CreateRootIsolate"); - Dart_Isolate vm_isolate = nullptr; - fml::WeakPtr embedder_isolate; - - char* error = nullptr; - - // Since this is the root isolate, we fake a parent embedder data object. We - // cannot use unique_ptr here because the destructor is private (since the - // isolate lifecycle is entirely managed by the VM). - auto root_embedder_data = std::make_unique( - vm, // VM - std::move(isolate_snapshot), // isolate snapshot - task_runners, // task runners - std::move(resource_context), // resource context - std::move(unref_queue), // skia unref queue - advisory_script_uri, // advisory URI - advisory_script_entrypoint // advisory entrypoint - ); - - std::tie(vm_isolate, embedder_isolate) = CreateDartVMAndEmbedderObjectPair( - advisory_script_uri.c_str(), // advisory script URI - advisory_script_entrypoint.c_str(), // advisory script entrypoint - nullptr, // package root - nullptr, // package config - flags, // flags - root_embedder_data.get(), // parent embedder data - true, // is root isolate - &error // error (out) - ); - - if (error != nullptr) { - free(error); - } - - if (vm_isolate == nullptr) { - return {}; - } - - if (embedder_isolate) { - // Only root isolates can interact with windows. - embedder_isolate->SetWindow(std::move(window)); - embedder_isolate->set_use_blink(vm->GetSettings().using_blink); - } - - return embedder_isolate; -} - -DartIsolate::DartIsolate(const DartVM* vm, - fxl::RefPtr isolate_snapshot, - TaskRunners task_runners, - fml::WeakPtr resource_context, - fxl::RefPtr unref_queue, - std::string advisory_script_uri, - std::string advisory_script_entrypoint) - : UIDartState(std::move(task_runners), - vm->GetSettings().task_observer_add, - vm->GetSettings().task_observer_remove, - std::move(resource_context), - std::move(unref_queue), - advisory_script_uri, - advisory_script_entrypoint, - vm->GetSettings().log_tag), - vm_(vm), - isolate_snapshot_(std::move(isolate_snapshot)), - weak_factory_(this) { - FXL_DCHECK(isolate_snapshot_) << "Must contain a valid isolate snapshot."; - weak_prototype_ = weak_factory_.GetWeakPtr(); - - if (vm_ == nullptr) { - return; - } - - phase_ = Phase::Uninitialized; -} - -DartIsolate::~DartIsolate() = default; - -DartIsolate::Phase DartIsolate::GetPhase() const { - return phase_; -} - -const DartVM* DartIsolate::GetDartVM() const { - return vm_; -} - -bool DartIsolate::Initialize(Dart_Isolate dart_isolate, bool is_root_isolate) { - TRACE_EVENT0("flutter", "DartIsolate::Initialize"); - if (phase_ != Phase::Uninitialized) { - return false; - } - - if (dart_isolate == nullptr) { - return false; - } - - if (Dart_CurrentIsolate() != dart_isolate) { - return false; - } - - if (Dart_IsolateData(dart_isolate) != this) { - return false; - } - - // After this point, isolate scopes can be safely used. - SetIsolate(dart_isolate); - - // We are entering a new scope (for the first time since initialization) and - // we want to restore the current scope to null when we exit out of this - // method. This balances the implicit Dart_EnterIsolate call made by - // Dart_CreateIsolate (which calls the Initialize). - Dart_ExitIsolate(); - - tonic::DartIsolateScope scope(isolate()); - - if (is_root_isolate) { - if (auto task_runner = GetTaskRunners().GetUITaskRunner()) { - // Isolates may not have any particular thread affinity. Only initialize - // the message handler if a task runner is explicitly specified. - message_handler().Initialize(task_runner); - } - } - - if (tonic::LogIfError( - Dart_SetLibraryTagHandler(tonic::DartState::HandleLibraryTag))) { - return false; - } - - if (!UpdateThreadPoolNames()) { - return false; - } - - phase_ = Phase::Initialized; - return true; -} - -// Updating thread names here does not change the underlying OS thread names. -// Instead, this is just additional metadata for the Observatory to show the -// thread name of the isolate. -bool DartIsolate::UpdateThreadPoolNames() const { - // TODO(chinmaygarde): This implementation does not account for multiple - // shells sharing the same (or subset of) threads. - const auto& task_runners = GetTaskRunners(); - - if (auto task_runner = task_runners.GetGPUTaskRunner()) { - task_runner->PostTask( - [label = task_runners.GetLabel() + std::string{".gpu"}]() { - Dart_SetThreadName(label.c_str()); - }); - } - - if (auto task_runner = task_runners.GetUITaskRunner()) { - task_runner->PostTask( - [label = task_runners.GetLabel() + std::string{".ui"}]() { - Dart_SetThreadName(label.c_str()); - }); - } - - if (auto task_runner = task_runners.GetIOTaskRunner()) { - task_runner->PostTask( - [label = task_runners.GetLabel() + std::string{".io"}]() { - Dart_SetThreadName(label.c_str()); - }); - } - - if (auto task_runner = task_runners.GetPlatformTaskRunner()) { - task_runner->PostTask( - [label = task_runners.GetLabel() + std::string{".platform"}]() { - Dart_SetThreadName(label.c_str()); - }); - } - - return true; -} - -bool DartIsolate::LoadLibraries() { - TRACE_EVENT0("flutter", "DartIsolate::LoadLibraries"); - if (phase_ != Phase::Initialized) { - return false; - } - - tonic::DartState::Scope scope(this); - - DartIO::InitForIsolate(); - - DartUI::InitForIsolate(); - - const bool is_service_isolate = Dart_IsServiceIsolate(isolate()); - - DartRuntimeHooks::Install(is_service_isolate - ? DartRuntimeHooks::SecondaryIsolate - : DartRuntimeHooks::MainIsolate, - GetAdvisoryScriptURI()); - - if (!is_service_isolate) { - class_library().add_provider( - "ui", std::make_unique(this, "dart:ui")); - } - - phase_ = Phase::LibrariesSetup; - return true; -} - -bool DartIsolate::PrepareForRunningFromPrecompiledCode() { - TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromPrecompiledCode"); - if (phase_ != Phase::LibrariesSetup) { - return false; - } - - if (!DartVM::IsRunningPrecompiledCode()) { - return false; - } - - tonic::DartState::Scope scope(this); - - if (Dart_IsNull(Dart_RootLibrary())) { - return false; - } - - if (!MarkIsolateRunnable()) { - return false; - } - - phase_ = Phase::Ready; - return true; -} - -static bool LoadScriptSnapshot(std::unique_ptr mapping) { - if (tonic::LogIfError(Dart_LoadScriptFromSnapshot(mapping->GetMapping(), - mapping->GetSize()))) { - return false; - } - return true; -} - -static bool LoadKernelSnapshot(std::unique_ptr mapping) { - if (tonic::LogIfError(Dart_LoadScriptFromKernel(mapping->GetMapping(), - mapping->GetSize()))) { - return false; - } - - return true; -} - -static bool LoadSnapshot(std::unique_ptr mapping, - bool is_kernel) { - if (is_kernel) { - return LoadKernelSnapshot(std::move(mapping)); - } else { - return LoadScriptSnapshot(std::move(mapping)); - } - return false; -} - -FXL_WARN_UNUSED_RESULT -bool DartIsolate::PrepareForRunningFromSnapshot( - std::unique_ptr mapping) { - TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromSnapshot"); - if (phase_ != Phase::LibrariesSetup) { - return false; - } - - if (DartVM::IsRunningPrecompiledCode()) { - return false; - } - - if (!mapping || mapping->GetSize() == 0) { - return false; - } - - tonic::DartState::Scope scope(this); - - if (!Dart_IsNull(Dart_RootLibrary())) { - return false; - } - - if (!LoadSnapshot(std::move(mapping), vm_->GetPlatformKernel() != nullptr)) { - return false; - } - - if (Dart_IsNull(Dart_RootLibrary())) { - return false; - } - - if (!MarkIsolateRunnable()) { - return false; - } - - phase_ = Phase::Ready; - return true; -} - -static bool FileNameIsDill(const std::string& name) { - const std::string suffix = ".dill"; - - if (name.size() < suffix.size()) { - return false; - } - - if (name.rfind(suffix, name.size()) == name.size() - suffix.size()) { - return true; - } - return false; -} - -bool DartIsolate::PrepareForRunningFromSource( - const std::string& main_source_file, - const std::string& packages) { - TRACE_EVENT0("flutter", "DartIsolate::PrepareForRunningFromSource"); - if (phase_ != Phase::LibrariesSetup) { - return false; - } - - if (DartVM::IsRunningPrecompiledCode()) { - return false; - } - - if (main_source_file.empty()) { - return false; - } - - tonic::DartState::Scope scope(this); - - if (!Dart_IsNull(Dart_RootLibrary())) { - return false; - } - - auto& loader = file_loader(); - - if (!packages.empty()) { - auto packages_absolute_path = files::AbsolutePath(packages); - FXL_DLOG(INFO) << "Loading from packages: " << packages_absolute_path; - if (!loader.LoadPackagesMap(packages_absolute_path)) { - return false; - } - } - - auto main_source_absolute_path = files::AbsolutePath(main_source_file); - FXL_DLOG(INFO) << "Loading from source: " << main_source_absolute_path; - - // The "source" file may be a ".dill" file. - if (FileNameIsDill(main_source_absolute_path)) { - auto mapping = - std::make_unique(main_source_absolute_path, false); - if (mapping == nullptr) { - return false; - } - if (!LoadKernelSnapshot(std::move(mapping))) { - return false; - } - } else { - if (tonic::LogIfError(loader.LoadScript(main_source_absolute_path))) { - return false; - } - } - - if (Dart_IsNull(Dart_RootLibrary())) { - return false; - } - - if (!MarkIsolateRunnable()) { - return false; - } - - phase_ = Phase::Ready; - return true; -} - -bool DartIsolate::MarkIsolateRunnable() { - TRACE_EVENT0("flutter", "DartIsolate::MarkIsolateRunnable"); - if (phase_ != Phase::LibrariesSetup) { - return false; - } - - // This function may only be called from an active isolate scope. - if (Dart_CurrentIsolate() != isolate()) { - return false; - } - - // There must be no current isolate to mark an isolate as being runnable. - Dart_ExitIsolate(); - - if (!Dart_IsolateMakeRunnable(isolate())) { - // Failed. Restore the isolate. - Dart_EnterIsolate(isolate()); - return false; - } - // Success. Restore the isolate. - Dart_EnterIsolate(isolate()); - return true; -} - -FXL_WARN_UNUSED_RESULT -bool DartIsolate::Run(const std::string& entrypoint_name) { - TRACE_EVENT0("flutter", "DartIsolate::Run"); - if (phase_ != Phase::Ready) { - return false; - } - - tonic::DartState::Scope scope(this); - - Dart_Handle entrypoint = Dart_GetClosure( - Dart_RootLibrary(), tonic::ToDart(entrypoint_name.c_str())); - if (tonic::LogIfError(entrypoint)) { - return false; - } - - Dart_Handle isolate_lib = Dart_LookupLibrary(tonic::ToDart("dart:isolate")); - if (tonic::LogIfError(isolate_lib)) { - return false; - } - - Dart_Handle isolate_args[] = { - entrypoint, - Dart_Null(), - }; - - if (tonic::LogIfError(Dart_Invoke( - isolate_lib, tonic::ToDart("_startMainIsolate"), - sizeof(isolate_args) / sizeof(isolate_args[0]), isolate_args))) { - return false; - } - - phase_ = Phase::Running; - return true; -} - -bool DartIsolate::Shutdown() { - TRACE_EVENT0("flutter", "DartIsolate::Shutdown"); - // This call may be re-entrant since Dart_ShutdownIsolate can invoke the - // cleanup callback which deletes the embedder side object of the dart isolate - // (a.k.a. this). - if (phase_ == Phase::Shutdown) { - return false; - } - phase_ = Phase::Shutdown; - Dart_Isolate vm_isolate = isolate(); - // The isolate can be nullptr if this instance is the stub isolate data used - // during root isolate creation. - if (vm_isolate != nullptr) { - // We need to enter the isolate because Dart_ShutdownIsolate does not take - // the isolate to shutdown as a parameter. - FXL_DCHECK(Dart_CurrentIsolate() == nullptr); - Dart_EnterIsolate(vm_isolate); - Dart_ShutdownIsolate(); - FXL_DCHECK(Dart_CurrentIsolate() == nullptr); - } - return true; -} - -static Dart_Isolate DartCreateAndStartServiceIsolate( - const char* advisory_script_uri, - const char* advisory_script_entrypoint, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - char** error) { - auto vm = DartVM::ForProcessIfInitialized(); - - if (!vm) { - *error = strdup( - "Could not resolve the VM when attempting to create the service " - "isolate."); - return nullptr; - } - - const auto& settings = vm->GetSettings(); - - if (!settings.enable_observatory) { - FXL_DLOG(INFO) << "Observatory is disabled."; - return nullptr; - } - - blink::TaskRunners null_task_runners( - "io.flutter." DART_VM_SERVICE_ISOLATE_NAME, nullptr, nullptr, nullptr, - nullptr); - - flags->load_vmservice_library = true; - - auto service_isolate = DartIsolate::CreateRootIsolate( - vm.get(), // vm - vm->GetIsolateSnapshot(), // isolate snapshot - null_task_runners, // task runners - nullptr, // window - {}, // resource context - {}, // unref queue - advisory_script_uri == nullptr ? "" : advisory_script_uri, // script uri - advisory_script_entrypoint == nullptr - ? "" - : advisory_script_entrypoint, // script entrypoint - flags // flags - ); - - if (!service_isolate) { - *error = strdup("Could not create the service isolate."); - FXL_DLOG(ERROR) << *error; - return nullptr; - } - - // The engine never holds a strong reference to the VM service isolate. Since - // we are about to lose our last weak reference to it, start the VM service - // while we have this reference. - - const bool running_from_sources = - !DartVM::IsRunningPrecompiledCode() && vm->GetPlatformKernel() == nullptr; - - tonic::DartState::Scope scope(service_isolate.get()); - if (!DartServiceIsolate::Startup( - settings.ipv6 ? "::1" : "127.0.0.1", // server IP address - settings.observatory_port, // server observatory port - tonic::DartState::HandleLibraryTag, // embedder library tag handler - running_from_sources, // running from source code - false, // disable websocket origin check - error // error (out) - )) { - // Error is populated by call to startup. - FXL_DLOG(ERROR) << *error; - return nullptr; - } - - vm->GetServiceProtocol().ToggleHooks(true); - - return service_isolate->isolate(); -} - -// |Dart_IsolateCreateCallback| -Dart_Isolate DartIsolate::DartIsolateCreateCallback( - const char* advisory_script_uri, - const char* advisory_script_entrypoint, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - DartIsolate* parent_embedder_isolate, - char** error) { - if (parent_embedder_isolate == nullptr && - strcmp(advisory_script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) { - // The VM attempts to start the VM service for us on |Dart_Initialize|. In - // such a case, the callback data will be null and the script URI will be - // DART_VM_SERVICE_ISOLATE_NAME. In such cases, we just create the service - // isolate like normal but dont hold a reference to it at all. We also start - // this isolate since we will never again reference it from the engine. - return DartCreateAndStartServiceIsolate(advisory_script_uri, // - advisory_script_entrypoint, // - package_root, // - package_config, // - flags, // - error // - ); - } - - return CreateDartVMAndEmbedderObjectPair( - advisory_script_uri, // URI - advisory_script_entrypoint, // entrypoint - package_root, // package root - package_config, // package config - flags, // isolate flags - parent_embedder_isolate, // embedder data - false, // is root isolate - error // error - ) - .first; -} - -std::pair> -DartIsolate::CreateDartVMAndEmbedderObjectPair( - const char* advisory_script_uri, - const char* advisory_script_entrypoint, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - DartIsolate* parent_embedder_isolate, - bool is_root_isolate, - char** error) { - TRACE_EVENT0("flutter", "DartIsolate::CreateDartVMAndEmbedderObjectPair"); - if (parent_embedder_isolate == nullptr || - parent_embedder_isolate->GetDartVM() == nullptr) { - *error = - strdup("Parent isolate did not have embedder specific callback data."); - FXL_DLOG(ERROR) << *error; - return {nullptr, {}}; - } - - const DartVM* vm = parent_embedder_isolate->GetDartVM(); - - // Create the native object on the embedder side. This object is deleted in - // the cleanup callback. - auto embedder_isolate = std::make_unique( - vm, // - parent_embedder_isolate->GetIsolateSnapshot(), // - parent_embedder_isolate->GetTaskRunners(), // - parent_embedder_isolate->GetResourceContext(), // - parent_embedder_isolate->GetSkiaUnrefQueue(), // - advisory_script_uri, // - advisory_script_entrypoint // - ); - - // Create the Dart VM isolate and give it the embedder object as the baton. - Dart_Isolate isolate = - vm->GetPlatformKernel() != nullptr - ? Dart_CreateIsolateFromKernel(advisory_script_uri, // - advisory_script_entrypoint, // - vm->GetPlatformKernel(), // - flags, // - embedder_isolate.get(), // - error // - ) - : Dart_CreateIsolate(advisory_script_uri, // - advisory_script_entrypoint, // - embedder_isolate->GetIsolateSnapshot() - ->GetData() - ->GetSnapshotPointer(), // - embedder_isolate->GetIsolateSnapshot() - ->GetInstructionsIfPresent(), // - flags, // - embedder_isolate.get(), // - error // - ); - - if (isolate == nullptr) { - FXL_DLOG(ERROR) << *error; - return {nullptr, {}}; - } - - if (!embedder_isolate->Initialize(isolate, is_root_isolate)) { - *error = strdup("Embedder could not initialize the Dart isolate."); - FXL_DLOG(ERROR) << *error; - return {nullptr, {}}; - } - - if (!embedder_isolate->LoadLibraries()) { - *error = - strdup("Embedder could not load libraries in the new Dart isolate."); - FXL_DLOG(ERROR) << *error; - return {nullptr, {}}; - } - - // The ownership of the embedder object is controlled by the Dart VM. So the - // only reference returned to the caller is weak. - return {isolate, embedder_isolate.release()->GetWeakIsolatePtr()}; -} - -// |Dart_IsolateShutdownCallback| -void DartIsolate::DartIsolateShutdownCallback(DartIsolate* embedder_isolate) { - if (!tonic::DartStickyError::IsSet()) { - return; - } - - tonic::DartApiScope api_scope; - FXL_LOG(ERROR) << "Isolate " << tonic::StdStringFromDart(Dart_DebugName()) - << " exited with an error"; - Dart_Handle sticky_error = Dart_GetStickyError(); - FXL_CHECK(tonic::LogIfError(sticky_error)); -} - -// |Dart_IsolateCleanupCallback| -void DartIsolate::DartIsolateCleanupCallback(DartIsolate* embedder_isolate) { - delete embedder_isolate; -} - -fxl::RefPtr DartIsolate::GetIsolateSnapshot() const { - return isolate_snapshot_; -} - -fml::WeakPtr DartIsolate::GetWeakIsolatePtr() const { - return weak_prototype_; -} - -void DartIsolate::AddIsolateShutdownCallback(fxl::Closure closure) { - shutdown_callbacks_.emplace_back( - std::make_unique(std::move(closure))); -} - -} // namespace blink diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h deleted file mode 100644 index 13d573ebe333f..0000000000000 --- a/runtime/dart_isolate.h +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2017 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_RUNTIME_DART_ISOLATE_H_ -#define FLUTTER_RUNTIME_DART_ISOLATE_H_ - -#include -#include - -#include "flutter/common/task_runners.h" -#include "flutter/fml/mapping.h" -#include "flutter/lib/ui/ui_dart_state.h" -#include "flutter/lib/ui/window/window.h" -#include "flutter/runtime/dart_snapshot.h" -#include "lib/fxl/compiler_specific.h" -#include "lib/fxl/macros.h" -#include "lib/tonic/dart_state.h" -#include "third_party/dart/runtime/include/dart_api.h" - -namespace blink { -class DartVM; - -class DartIsolate : public UIDartState { - public: - enum class Phase { - Unknown, - Uninitialized, - Initialized, - LibrariesSetup, - Ready, - Running, - Shutdown, - }; - - // The root isolate of a Flutter application is special because it gets Window - // bindings. From the VM's perspective, this isolate is not special in any - // way. - static fml::WeakPtr CreateRootIsolate( - const DartVM* vm, - fxl::RefPtr isolate_snapshot, - TaskRunners task_runners, - std::unique_ptr window, - fml::WeakPtr resource_context, - fxl::RefPtr unref_queue, - std::string advisory_script_uri = "main.dart", - std::string advisory_script_entrypoint = "main", - Dart_IsolateFlags* flags = nullptr); - - DartIsolate(const DartVM* vm, - fxl::RefPtr isolate_snapshot, - TaskRunners task_runners, - fml::WeakPtr resource_context, - fxl::RefPtr unref_queue, - std::string advisory_script_uri, - std::string advisory_script_entrypoint); - - ~DartIsolate() override; - - Phase GetPhase() const; - - FXL_WARN_UNUSED_RESULT - bool PrepareForRunningFromPrecompiledCode(); - - FXL_WARN_UNUSED_RESULT - bool PrepareForRunningFromSnapshot(std::unique_ptr snapshot); - - FXL_WARN_UNUSED_RESULT - bool PrepareForRunningFromSource(const std::string& main_source_file, - const std::string& packages); - - FXL_WARN_UNUSED_RESULT - bool Run(const std::string& entrypoint); - - FXL_WARN_UNUSED_RESULT - bool Shutdown(); - - void AddIsolateShutdownCallback(fxl::Closure closure); - - const DartVM* GetDartVM() const; - - fxl::RefPtr GetIsolateSnapshot() const; - - fml::WeakPtr GetWeakIsolatePtr() const; - - private: - class AutoFireClosure { - public: - AutoFireClosure(fxl::Closure closure) : closure_(std::move(closure)) {} - ~AutoFireClosure() { - if (closure_) { - closure_(); - } - } - - private: - fxl::Closure closure_; - FXL_DISALLOW_COPY_AND_ASSIGN(AutoFireClosure); - }; - friend class DartVM; - - const DartVM* vm_ = nullptr; - Phase phase_ = Phase::Unknown; - const fxl::RefPtr isolate_snapshot_; - std::vector> shutdown_callbacks_; - fml::WeakPtr weak_prototype_; - fml::WeakPtrFactory weak_factory_; - - FXL_WARN_UNUSED_RESULT - bool Initialize(Dart_Isolate isolate, bool is_root_isolate); - - FXL_WARN_UNUSED_RESULT - bool LoadLibraries(); - - bool UpdateThreadPoolNames() const; - - FXL_WARN_UNUSED_RESULT - bool MarkIsolateRunnable(); - - // |Dart_IsolateCreateCallback| - static Dart_Isolate DartIsolateCreateCallback( - const char* advisory_script_uri, - const char* advisory_script_entrypoint, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - DartIsolate* embedder_isolate, - char** error); - - static std::pair /* embedder */> - CreateDartVMAndEmbedderObjectPair(const char* advisory_script_uri, - const char* advisory_script_entrypoint, - const char* package_root, - const char* package_config, - Dart_IsolateFlags* flags, - DartIsolate* parent_embedder_isolate, - bool is_root_isolate, - char** error); - - // |Dart_IsolateShutdownCallback| - static void DartIsolateShutdownCallback(DartIsolate* embedder_isolate); - - // |Dart_IsolateCleanupCallback| - static void DartIsolateCleanupCallback(DartIsolate* embedder_isolate); - - FXL_DISALLOW_COPY_AND_ASSIGN(DartIsolate); -}; - -} // namespace blink - -#endif // FLUTTER_RUNTIME_DART_ISOLATE_H_ diff --git a/runtime/dart_isolate_unittests.cc b/runtime/dart_isolate_unittests.cc deleted file mode 100644 index d8f2e02382da1..0000000000000 --- a/runtime/dart_isolate_unittests.cc +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/fml/thread.h" -#include "flutter/runtime/dart_isolate.h" -#include "flutter/runtime/dart_vm.h" -#include "flutter/testing/testing.h" -#include "flutter/testing/thread_test.h" - -#define CURRENT_TEST_NAME \ - std::string { \ - ::testing::UnitTest::GetInstance()->current_test_info()->name() \ - } - -namespace blink { - -using DartIsolateTest = ::testing::ThreadTest; - -TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) { - Settings settings = {}; - settings.task_observer_add = [](intptr_t, fxl::Closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - auto vm = DartVM::ForProcess(settings); - ASSERT_TRUE(vm); - TaskRunners task_runners(CURRENT_TEST_NAME, // - GetCurrentTaskRunner(), // - GetCurrentTaskRunner(), // - GetCurrentTaskRunner(), // - GetCurrentTaskRunner() // - ); - auto root_isolate = DartIsolate::CreateRootIsolate( - vm.get(), // vm - vm->GetIsolateSnapshot(), // isolate snapshot - std::move(task_runners), // task runners - nullptr, // window - {}, // resource context - nullptr // unref qeueue - ); - ASSERT_TRUE(root_isolate); - ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); - ASSERT_TRUE(root_isolate->Shutdown()); -} - -TEST_F(DartIsolateTest, IsolateCanAssociateSnapshot) { - Settings settings = {}; - settings.task_observer_add = [](intptr_t, fxl::Closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - auto vm = DartVM::ForProcess(settings); - ASSERT_TRUE(vm); - TaskRunners task_runners(CURRENT_TEST_NAME, // - GetCurrentTaskRunner(), // - GetCurrentTaskRunner(), // - GetCurrentTaskRunner(), // - GetCurrentTaskRunner() // - ); - auto root_isolate = DartIsolate::CreateRootIsolate( - vm.get(), // vm - vm->GetIsolateSnapshot(), // isolate snapshot - std::move(task_runners), // task runners - nullptr, // window - {}, // resource context - nullptr // unref qeueue - ); - ASSERT_TRUE(root_isolate); - ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); - ASSERT_TRUE(root_isolate->PrepareForRunningFromSource( - testing::GetFixturesPath() + std::string{"/simple_main.dart"}, "")); - ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Ready); - ASSERT_TRUE(root_isolate->Shutdown()); -} - -TEST_F(DartIsolateTest, CanResolveAndInvokeMethod) { - Settings settings = {}; - settings.task_observer_add = [](intptr_t, fxl::Closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - auto vm = DartVM::ForProcess(settings); - ASSERT_TRUE(vm); - TaskRunners task_runners(CURRENT_TEST_NAME, // - GetCurrentTaskRunner(), // - GetCurrentTaskRunner(), // - GetCurrentTaskRunner(), // - GetCurrentTaskRunner() // - ); - auto root_isolate = DartIsolate::CreateRootIsolate( - vm.get(), // vm - vm->GetIsolateSnapshot(), // isolate snapshot - std::move(task_runners), // task runners - nullptr, // window - {}, // resource context - nullptr // unref qeueue - ); - ASSERT_TRUE(root_isolate); - ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::LibrariesSetup); - ASSERT_TRUE(root_isolate->PrepareForRunningFromSource( - testing::GetFixturesPath() + std::string{"/simple_main.dart"}, "")); - ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Ready); - ASSERT_TRUE(root_isolate->Run("simple_main")); - ASSERT_EQ(root_isolate->GetPhase(), DartIsolate::Phase::Running); - ASSERT_TRUE(root_isolate->Shutdown()); -} - -} // namespace blink diff --git a/runtime/dart_service_isolate.h b/runtime/dart_service_isolate.h index 59a02e2e9d495..9edd663feb6bd 100644 --- a/runtime/dart_service_isolate.h +++ b/runtime/dart_service_isolate.h @@ -13,6 +13,8 @@ namespace blink { class DartServiceIsolate { public: + static bool Bootstrap(); + static bool Startup(std::string server_ip, intptr_t server_port, Dart_LibraryTagHandler embedder_tag_handler, diff --git a/runtime/dart_snapshot.cc b/runtime/dart_snapshot.cc deleted file mode 100644 index 5d759257d1d4b..0000000000000 --- a/runtime/dart_snapshot.cc +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/runtime/dart_snapshot.h" - -#include - -#include "flutter/fml/native_library.h" -#include "flutter/fml/paths.h" -#include "flutter/fml/trace_event.h" -#include "flutter/runtime/dart_snapshot_buffer.h" -#include "flutter/runtime/dart_vm.h" - -namespace blink { - -const char* DartSnapshot::kVMDataSymbol = "kDartVmSnapshotData"; -const char* DartSnapshot::kVMInstructionsSymbol = "kDartVmSnapshotInstructions"; -const char* DartSnapshot::kIsolateDataSymbol = "kDartIsolateSnapshotData"; -const char* DartSnapshot::kIsolateInstructionsSymbol = - "kDartIsolateSnapshotInstructions"; - -static std::unique_ptr ResolveVMData( - const Settings& settings) { - if (settings.aot_snapshot_path.size() > 0) { - auto path = fml::paths::JoinPaths( - {settings.aot_snapshot_path, settings.aot_vm_snapshot_data_filename}); - if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( - path.c_str(), false /* executable */)) { - return source; - } - } - - auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); - return DartSnapshotBuffer::CreateWithSymbolInLibrary( - loaded_process, DartSnapshot::kVMDataSymbol); -} - -static std::unique_ptr ResolveVMInstructions( - const Settings& settings) { - if (settings.aot_snapshot_path.size() > 0) { - auto path = fml::paths::JoinPaths( - {settings.aot_snapshot_path, settings.aot_vm_snapshot_instr_filename}); - if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( - path.c_str(), true /* executable */)) { - return source; - } - } - - if (settings.application_library_path.size() > 0) { - auto library = - fml::NativeLibrary::Create(settings.application_library_path.c_str()); - if (auto source = DartSnapshotBuffer::CreateWithSymbolInLibrary( - library, DartSnapshot::kVMInstructionsSymbol)) { - return source; - } - } - - auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); - return DartSnapshotBuffer::CreateWithSymbolInLibrary( - loaded_process, DartSnapshot::kVMInstructionsSymbol); -} - -static std::unique_ptr ResolveIsolateData( - const Settings& settings) { - if (settings.aot_snapshot_path.size() > 0) { - auto path = - fml::paths::JoinPaths({settings.aot_snapshot_path, - settings.aot_isolate_snapshot_data_filename}); - if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( - path.c_str(), false /* executable */)) { - return source; - } - } - - auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); - return DartSnapshotBuffer::CreateWithSymbolInLibrary( - loaded_process, DartSnapshot::kIsolateDataSymbol); -} - -static std::unique_ptr ResolveIsolateInstructions( - const Settings& settings) { - if (settings.aot_snapshot_path.size() > 0) { - auto path = - fml::paths::JoinPaths({settings.aot_snapshot_path, - settings.aot_isolate_snapshot_instr_filename}); - if (auto source = DartSnapshotBuffer::CreateWithContentsOfFile( - path.c_str(), true /* executable */)) { - return source; - } - } - - if (settings.application_library_path.size() > 0) { - auto library = - fml::NativeLibrary::Create(settings.application_library_path.c_str()); - if (auto source = DartSnapshotBuffer::CreateWithSymbolInLibrary( - library, DartSnapshot::kIsolateInstructionsSymbol)) { - return source; - } - } - - auto loaded_process = fml::NativeLibrary::CreateForCurrentProcess(); - return DartSnapshotBuffer::CreateWithSymbolInLibrary( - loaded_process, DartSnapshot::kIsolateInstructionsSymbol); -} - -fxl::RefPtr DartSnapshot::VMSnapshotFromSettings( - const Settings& settings) { - TRACE_EVENT0("flutter", "DartSnapshot::VMSnapshotFromSettings"); - auto snapshot = - fxl::MakeRefCounted(ResolveVMData(settings), // - ResolveVMInstructions(settings) // - ); - if (snapshot->IsValid()) { - return snapshot; - } - return nullptr; -} - -fxl::RefPtr DartSnapshot::IsolateSnapshotFromSettings( - const Settings& settings) { - TRACE_EVENT0("flutter", "DartSnapshot::IsolateSnapshotFromSettings"); - auto snapshot = - fxl::MakeRefCounted(ResolveIsolateData(settings), // - ResolveIsolateInstructions(settings) // - ); - if (snapshot->IsValid()) { - return snapshot; - } - return nullptr; -} - -DartSnapshot::DartSnapshot(std::unique_ptr data, - std::unique_ptr instructions) - : data_(std::move(data)), instructions_(std::move(instructions)) {} - -DartSnapshot::~DartSnapshot() = default; - -bool DartSnapshot::IsValid() const { - return static_cast(data_); -} - -bool DartSnapshot::IsValidForAOT() const { - return data_ && instructions_; -} - -const DartSnapshotBuffer* DartSnapshot::GetData() const { - return data_.get(); -} - -const DartSnapshotBuffer* DartSnapshot::GetInstructions() const { - return instructions_.get(); -} - -const uint8_t* DartSnapshot::GetInstructionsIfPresent() const { - return instructions_ ? instructions_->GetSnapshotPointer() : nullptr; -} - -} // namespace blink diff --git a/runtime/dart_snapshot.h b/runtime/dart_snapshot.h deleted file mode 100644 index 4f04765b4f5a9..0000000000000 --- a/runtime/dart_snapshot.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2017 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_RUNTIME_DART_SNAPSHOT_H_ -#define FLUTTER_RUNTIME_DART_SNAPSHOT_H_ - -#include -#include - -#include "flutter/common/settings.h" -#include "flutter/runtime/dart_snapshot_buffer.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/ref_counted.h" - -namespace blink { - -class DartSnapshot : public fxl::RefCountedThreadSafe { - public: - static const char* kVMDataSymbol; - static const char* kVMInstructionsSymbol; - static const char* kIsolateDataSymbol; - static const char* kIsolateInstructionsSymbol; - - static fxl::RefPtr VMSnapshotFromSettings( - const Settings& settings); - - static fxl::RefPtr IsolateSnapshotFromSettings( - const Settings& settings); - - bool IsValid() const; - - bool IsValidForAOT() const; - - const DartSnapshotBuffer* GetData() const; - - const DartSnapshotBuffer* GetInstructions() const; - - const uint8_t* GetInstructionsIfPresent() const; - - private: - std::unique_ptr data_; - std::unique_ptr instructions_; - - DartSnapshot(std::unique_ptr data, - std::unique_ptr instructions); - - ~DartSnapshot(); - - FRIEND_REF_COUNTED_THREAD_SAFE(DartSnapshot); - FRIEND_MAKE_REF_COUNTED(DartSnapshot); - FXL_DISALLOW_COPY_AND_ASSIGN(DartSnapshot); -}; - -} // namespace blink - -#endif // FLUTTER_RUNTIME_DART_SNAPSHOT_H_ diff --git a/runtime/dart_snapshot_buffer.cc b/runtime/dart_snapshot_buffer.cc deleted file mode 100644 index c39233ac8334a..0000000000000 --- a/runtime/dart_snapshot_buffer.cc +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/runtime/dart_snapshot_buffer.h" - -#include - -#include "flutter/fml/mapping.h" - -namespace blink { - -class NativeLibrarySnapshotBuffer final : public DartSnapshotBuffer { - public: - NativeLibrarySnapshotBuffer(fxl::RefPtr library, - const char* symbol_name) - : library_(std::move(library)) { - if (library_) { - symbol_ = library_->ResolveSymbol(symbol_name); - } - } - - const uint8_t* GetSnapshotPointer() const override { return symbol_; } - - size_t GetSnapshotSize() const override { return 0; } - - private: - fxl::RefPtr library_; - const uint8_t* symbol_ = nullptr; - - FXL_DISALLOW_COPY_AND_ASSIGN(NativeLibrarySnapshotBuffer); -}; - -class FileSnapshotBuffer final : public DartSnapshotBuffer { - public: - FileSnapshotBuffer(const char* path, bool executable) - : mapping_(path, executable) { - if (mapping_.GetSize() > 0) { - symbol_ = mapping_.GetMapping(); - } - } - - const uint8_t* GetSnapshotPointer() const override { return symbol_; } - - size_t GetSnapshotSize() const override { return mapping_.GetSize(); } - - private: - fml::FileMapping mapping_; - const uint8_t* symbol_ = nullptr; - - FXL_DISALLOW_COPY_AND_ASSIGN(FileSnapshotBuffer); -}; - -std::unique_ptr -DartSnapshotBuffer::CreateWithSymbolInLibrary( - fxl::RefPtr library, - const char* symbol_name) { - auto source = std::make_unique( - std::move(library), symbol_name); - return source->GetSnapshotPointer() == nullptr ? nullptr : std::move(source); -} - -std::unique_ptr -DartSnapshotBuffer::CreateWithContentsOfFile(const char* file_path, - bool executable) { - auto source = std::make_unique(file_path, executable); - return source->GetSnapshotPointer() == nullptr ? nullptr : std::move(source); -} - -DartSnapshotBuffer::~DartSnapshotBuffer() = default; - -} // namespace blink diff --git a/runtime/dart_snapshot_buffer.h b/runtime/dart_snapshot_buffer.h deleted file mode 100644 index 675946c0ca63f..0000000000000 --- a/runtime/dart_snapshot_buffer.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 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_RUNTIME_DART_SNAPSHOT_BUFFER_H_ -#define FLUTTER_RUNTIME_DART_SNAPSHOT_BUFFER_H_ - -#include - -#include "flutter/fml/native_library.h" -#include "lib/fxl/macros.h" - -namespace blink { - -class DartSnapshotBuffer { - public: - static std::unique_ptr CreateWithSymbolInLibrary( - fxl::RefPtr library, - const char* symbol_name); - - static std::unique_ptr CreateWithContentsOfFile( - const char* file_path, - bool executable); - - virtual ~DartSnapshotBuffer(); - - virtual const uint8_t* GetSnapshotPointer() const = 0; - - virtual size_t GetSnapshotSize() const = 0; -}; - -} // namespace blink - -#endif // FLUTTER_RUNTIME_DART_SNAPSHOT_BUFFER_H_ diff --git a/runtime/dart_vm.cc b/runtime/dart_vm.cc deleted file mode 100644 index bb46779078583..0000000000000 --- a/runtime/dart_vm.cc +++ /dev/null @@ -1,472 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/runtime/dart_vm.h" - -#include - -#include -#include - -#include "flutter/common/settings.h" -#include "flutter/fml/trace_event.h" -#include "flutter/lib/io/dart_io.h" -#include "flutter/lib/ui/dart_runtime_hooks.h" -#include "flutter/lib/ui/dart_ui.h" -#include "flutter/runtime/dart_isolate.h" -#include "flutter/runtime/dart_service_isolate.h" -#include "flutter/runtime/start_up.h" -#include "lib/fxl/arraysize.h" -#include "lib/fxl/compiler_specific.h" -#include "lib/fxl/files/file.h" -#include "lib/fxl/logging.h" -#include "lib/fxl/time/time_delta.h" -#include "lib/tonic/converter/dart_converter.h" -#include "lib/tonic/dart_class_library.h" -#include "lib/tonic/dart_class_provider.h" -#include "lib/tonic/dart_sticky_error.h" -#include "lib/tonic/file_loader/file_loader.h" -#include "lib/tonic/logging/dart_error.h" -#include "lib/tonic/scopes/dart_api_scope.h" -#include "lib/tonic/typed_data/uint8_list.h" -#include "third_party/dart/runtime/bin/embedded_dart_io.h" - -#ifdef ERROR -#undef ERROR -#endif - -namespace dart { -namespace observatory { - -#if !OS(FUCHSIA) && (FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE) - -// These two symbols are defined in |observatory_archive.cc| which is generated -// by the |//third_party/dart/runtime/observatory:archive_observatory| rule. -// Both of these symbols will be part of the data segment and therefore are read -// only. -extern unsigned int observatory_assets_archive_len; -extern const uint8_t* observatory_assets_archive; - -#endif // !OS(FUCHSIA) && (FLUTTER_RUNTIME_MODE != - // FLUTTER_RUNTIME_MODE_RELEASE) - -} // namespace observatory -} // namespace dart - -namespace blink { - -// Arguments passed to the Dart VM in all configurations. -static const char* kDartLanguageArgs[] = { - "--enable_mirrors=false", "--background_compilation", "--await_is_keyword", - "--causal_async_stacks", "--limit-ints-to-64-bits", -}; - -static const char* kDartPrecompilationArgs[] = { - "--precompilation", -}; - -FXL_ALLOW_UNUSED_TYPE -static const char* kDartWriteProtectCodeArgs[] = { - "--no_write_protect_code", -}; - -static const char* kDartAssertArgs[] = { - // clang-format off - "--enable_asserts", - // clang-format on -}; - -static const char* kDartCheckedModeArgs[] = { - // clang-format off - "--enable_type_checks", - "--error_on_bad_type", - "--error_on_bad_override", - // clang-format on -}; - -static const char* kDartStrongModeArgs[] = { - // clang-format off - "--strong", - "--reify_generic_functions", - "--limit_ints_to_64_bits", - "--sync_async", - // clang-format on -}; - -static const char* kDartStartPausedArgs[]{ - "--pause_isolates_on_start", -}; - -static const char* kDartTraceStartupArgs[]{ - "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,VM", -}; - -static const char* kDartEndlessTraceBufferArgs[]{ - "--timeline_recorder=endless", -}; - -static const char* kDartFuchsiaTraceArgs[] FXL_ALLOW_UNUSED_TYPE = { - "--systrace_timeline", - "--timeline_streams=Compiler,Dart,Debugger,Embedder,GC,Isolate,VM", -}; - -constexpr char kFileUriPrefix[] = "file://"; -constexpr size_t kFileUriPrefixLength = sizeof(kFileUriPrefix) - 1; - -bool DartFileModifiedCallback(const char* source_url, int64_t since_ms) { - if (strncmp(source_url, kFileUriPrefix, kFileUriPrefixLength) != 0u) { - // Assume modified. - return true; - } - - const char* path = source_url + kFileUriPrefixLength; - struct stat info; - if (stat(path, &info) < 0) - return true; - - // If st_mtime is zero, it's more likely that the file system doesn't support - // mtime than that the file was actually modified in the 1970s. - if (!info.st_mtime) - return true; - - // It's very unclear what time bases we're with here. The Dart API doesn't - // document the time base for since_ms. Reading the code, the value varies by - // platform, with a typical source being something like gettimeofday. - // - // We add one to st_mtime because st_mtime has less precision than since_ms - // and we want to treat the file as modified if the since time is between - // ticks of the mtime. - fxl::TimeDelta mtime = fxl::TimeDelta::FromSeconds(info.st_mtime + 1); - fxl::TimeDelta since = fxl::TimeDelta::FromMilliseconds(since_ms); - - return mtime > since; -} - -void ThreadExitCallback() {} - -Dart_Handle GetVMServiceAssetsArchiveCallback() { -#if (FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE) - return nullptr; -#elif OS(FUCHSIA) - std::vector observatory_assets_archive; - if (!files::ReadFileToVector("pkg/data/observatory.tar", - &observatory_assets_archive)) { - FXL_LOG(ERROR) << "Fail to load Observatory archive"; - return nullptr; - } - return tonic::DartConverter::ToDart( - observatory_assets_archive.data(), observatory_assets_archive.size()); -#else - return tonic::DartConverter::ToDart( - ::dart::observatory::observatory_assets_archive, - ::dart::observatory::observatory_assets_archive_len); -#endif -} - -static const char kStdoutStreamId[] = "Stdout"; -static const char kStderrStreamId[] = "Stderr"; - -static bool ServiceStreamListenCallback(const char* stream_id) { - if (strcmp(stream_id, kStdoutStreamId) == 0) { - dart::bin::SetCaptureStdout(true); - return true; - } else if (strcmp(stream_id, kStderrStreamId) == 0) { - dart::bin::SetCaptureStderr(true); - return true; - } - return false; -} - -static void ServiceStreamCancelCallback(const char* stream_id) { - if (strcmp(stream_id, kStdoutStreamId) == 0) { - dart::bin::SetCaptureStdout(false); - } else if (strcmp(stream_id, kStderrStreamId) == 0) { - dart::bin::SetCaptureStderr(false); - } -} - -bool DartVM::IsRunningPrecompiledCode() { - return Dart_IsPrecompiledRuntime(); -} - -static std::vector ProfilingFlags(bool enable_profiling) { -// Disable Dart's built in profiler when building a debug build. This -// works around a race condition that would sometimes stop a crash's -// stack trace from being printed on Android. -#ifndef NDEBUG - enable_profiling = false; -#endif - - // We want to disable profiling by default because it overwhelms LLDB. But - // the VM enables the same by default. In either case, we have some profiling - // flags. - if (enable_profiling) { - return {// This is the default. But just be explicit. - "--profiler", - // This instructs the profiler to walk C++ frames, and to include - // them in the profile. - "--profile-vm"}; - } else { - return {"--no-profiler"}; - } -} - -void PushBackAll(std::vector* args, - const char** argv, - size_t argc) { - for (size_t i = 0; i < argc; ++i) { - args->push_back(argv[i]); - } -} - -static void EmbedderInformationCallback(Dart_EmbedderInformation* info) { - info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION; - dart::bin::GetIOEmbedderInformation(info); - info->name = "Flutter"; -} - -fxl::RefPtr DartVM::ForProcess(Settings settings) { - return ForProcess(settings, nullptr, nullptr); -} - -static std::once_flag gVMInitialization; -static fxl::RefPtr gVM; - -fxl::RefPtr DartVM::ForProcess( - Settings settings, - fxl::RefPtr vm_snapshot, - fxl::RefPtr isolate_snapshot) { - std::call_once(gVMInitialization, [settings, // - vm_snapshot, // - isolate_snapshot // - ]() mutable { - if (!vm_snapshot) { - vm_snapshot = DartSnapshot::VMSnapshotFromSettings(settings); - } - if (!isolate_snapshot) { - isolate_snapshot = DartSnapshot::IsolateSnapshotFromSettings(settings); - } - gVM = fxl::MakeRefCounted(settings, // - std::move(vm_snapshot), // - std::move(isolate_snapshot) // - ); - }); - return gVM; -} - -fxl::RefPtr DartVM::ForProcessIfInitialized() { - return gVM; -} - -DartVM::DartVM(const Settings& settings, - fxl::RefPtr vm_snapshot, - fxl::RefPtr isolate_snapshot) - : settings_(settings), - vm_snapshot_(std::move(vm_snapshot)), - isolate_snapshot_(std::move(isolate_snapshot)), - platform_kernel_mapping_( - std::make_unique(settings.kernel_snapshot_path)), - weak_factory_(this) { - TRACE_EVENT0("flutter", "DartVMInitializer"); - FXL_DLOG(INFO) << "Attempting Dart VM launch for mode: " - << (IsRunningPrecompiledCode() ? "AOT" : "Interpreter"); - - FXL_DCHECK(vm_snapshot_ && vm_snapshot_->IsValid()) - << "VM snapshot must be valid."; - - FXL_DCHECK(isolate_snapshot_ && isolate_snapshot_->IsValid()) - << "Isolate snapshot must be valid."; - - if (platform_kernel_mapping_->GetSize() > 0) { - // The platform kernel mapping lifetime is managed by this instance of the - // DartVM and hence will exceed that of the PlatformKernel. So provide an - // empty release callback. - Dart_ReleaseBufferCallback empty = [](auto arg) {}; - platform_kernel_ = reinterpret_cast(Dart_ReadKernelBinary( - platform_kernel_mapping_->GetMapping(), // buffer - platform_kernel_mapping_->GetSize(), // buffer size - empty // buffer deleter - )); - } - - { - TRACE_EVENT0("flutter", "dart::bin::BootstrapDartIo"); - dart::bin::BootstrapDartIo(); - - if (!settings.temp_directory_path.empty()) { - dart::bin::SetSystemTempDirectory(settings.temp_directory_path.c_str()); - } - } - - std::vector args; - - // Instruct the VM to ignore unrecognized flags. - // There is a lot of diversity in a lot of combinations when it - // comes to the arguments the VM supports. And, if the VM comes across a flag - // it does not recognize, it exits immediately. - args.push_back("--ignore-unrecognized-flags"); - - for (const auto& profiler_flag : - ProfilingFlags(settings.enable_dart_profiling)) { - args.push_back(profiler_flag); - } - - PushBackAll(&args, kDartLanguageArgs, arraysize(kDartLanguageArgs)); - - if (IsRunningPrecompiledCode()) { - PushBackAll(&args, kDartPrecompilationArgs, - arraysize(kDartPrecompilationArgs)); - } - - // Enable checked mode if we are not running precompiled code. We run non- - // precompiled code only in the debug product mode. - bool use_checked_mode = !settings.dart_non_checked_mode; - -#if !OS(FUCHSIA) - if (IsRunningPrecompiledCode()) { - use_checked_mode = false; - } -#endif // !OS(FUCHSIA) - -#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_DEBUG - // Debug mode uses the JIT, disable code page write protection to avoid - // memory page protection changes before and after every compilation. - PushBackAll(&args, kDartWriteProtectCodeArgs, - arraysize(kDartWriteProtectCodeArgs)); -#endif - - const bool isolate_snapshot_is_dart_2 = - Dart_IsDart2Snapshot(isolate_snapshot_->GetData()->GetSnapshotPointer()); - - const bool is_preview_dart2 = - platform_kernel_ != nullptr || isolate_snapshot_is_dart_2; - - if (is_preview_dart2) { - FXL_DLOG(INFO) << "Dart 2 is enabled."; - } else { - FXL_DLOG(INFO) << "Dart 2 is NOT enabled. Platform kernel: " - << static_cast(platform_kernel_) - << " Isolate Snapshot is Dart 2: " - << isolate_snapshot_is_dart_2; - } - if (is_preview_dart2) { - PushBackAll(&args, kDartStrongModeArgs, arraysize(kDartStrongModeArgs)); - if (use_checked_mode) { - PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); - } - } else if (use_checked_mode) { - FXL_DLOG(INFO) << "Checked mode is ON"; - PushBackAll(&args, kDartAssertArgs, arraysize(kDartAssertArgs)); - PushBackAll(&args, kDartCheckedModeArgs, arraysize(kDartCheckedModeArgs)); - } else { - FXL_DLOG(INFO) << "Is not Dart 2 and Checked mode is OFF"; - } - - if (settings.start_paused) { - PushBackAll(&args, kDartStartPausedArgs, arraysize(kDartStartPausedArgs)); - } - - if (settings.endless_trace_buffer || settings.trace_startup) { - // If we are tracing startup, make sure the trace buffer is endless so we - // don't lose early traces. - PushBackAll(&args, kDartEndlessTraceBufferArgs, - arraysize(kDartEndlessTraceBufferArgs)); - } - - if (settings.trace_startup) { - PushBackAll(&args, kDartTraceStartupArgs, arraysize(kDartTraceStartupArgs)); - } - -#if defined(OS_FUCHSIA) - PushBackAll(&args, kDartFuchsiaTraceArgs, arraysize(kDartFuchsiaTraceArgs)); -#endif - - for (size_t i = 0; i < settings.dart_flags.size(); i++) - args.push_back(settings.dart_flags[i].c_str()); - - FXL_CHECK(Dart_SetVMFlags(args.size(), args.data())); - - DartUI::InitForGlobal(); - - { - TRACE_EVENT0("flutter", "Dart_Initialize"); - Dart_InitializeParams params = {}; - params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION; - params.vm_snapshot_data = vm_snapshot_->GetData()->GetSnapshotPointer(); - params.vm_snapshot_instructions = vm_snapshot_->GetInstructionsIfPresent(); - params.create = reinterpret_cast( - DartIsolate::DartIsolateCreateCallback); - params.shutdown = reinterpret_cast( - DartIsolate::DartIsolateShutdownCallback); - params.cleanup = reinterpret_cast( - DartIsolate::DartIsolateCleanupCallback); - params.thread_exit = ThreadExitCallback; - params.get_service_assets = GetVMServiceAssetsArchiveCallback; - params.entropy_source = DartIO::EntropySource; - char* init_error = Dart_Initialize(¶ms); - if (init_error) { - FXL_LOG(FATAL) << "Error while initializing the Dart VM: " << init_error; - ::free(init_error); - } - // Send the earliest available timestamp in the application lifecycle to - // timeline. The difference between this timestamp and the time we render - // the very first frame gives us a good idea about Flutter's startup time. - // Use a duration event so about:tracing will consider this event when - // deciding the earliest event to use as time 0. - if (blink::engine_main_enter_ts != 0) { - Dart_TimelineEvent("FlutterEngineMainEnter", // label - blink::engine_main_enter_ts, // timestamp0 - blink::engine_main_enter_ts, // timestamp1_or_async_id - Dart_Timeline_Event_Duration, // event type - 0, // argument_count - nullptr, // argument_names - nullptr // argument_values - ); - } - } - - // Allow streaming of stdout and stderr by the Dart vm. - Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback, - &ServiceStreamCancelCallback); - - Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback); -} - -DartVM::~DartVM() { - if (Dart_CurrentIsolate() != nullptr) { - Dart_ExitIsolate(); - } - char* result = Dart_Cleanup(); - if (result != nullptr) { - FXL_LOG(ERROR) << "Could not cleanly shut down the Dart VM. Message: \"" - << result << "\"."; - free(result); - } -} - -const Settings& DartVM::GetSettings() const { - return settings_; -} - -DartVM::PlatformKernel* DartVM::GetPlatformKernel() const { - return platform_kernel_; -} - -const DartSnapshot& DartVM::GetVMSnapshot() const { - return *vm_snapshot_.get(); -} - -fxl::RefPtr DartVM::GetIsolateSnapshot() const { - return isolate_snapshot_; -} - -ServiceProtocol& DartVM::GetServiceProtocol() { - return service_protocol_; -} - -fxl::WeakPtr DartVM::GetWeakPtr() { - return weak_factory_.GetWeakPtr(); -} - -} // namespace blink diff --git a/runtime/dart_vm.h b/runtime/dart_vm.h deleted file mode 100644 index e8feb9ba1de92..0000000000000 --- a/runtime/dart_vm.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2017 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_RUNTIME_DART_VM_H_ -#define FLUTTER_RUNTIME_DART_VM_H_ - -#include -#include -#include - -#include "flutter/common/settings.h" -#include "flutter/runtime/dart_isolate.h" -#include "flutter/runtime/dart_snapshot.h" -#include "flutter/runtime/service_protocol.h" -#include "lib/fxl/build_config.h" -#include "lib/fxl/functional/closure.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/ref_counted.h" -#include "lib/fxl/memory/ref_ptr.h" -#include "lib/fxl/memory/weak_ptr.h" -#include "third_party/dart/runtime/include/dart_api.h" - -namespace blink { - -class DartVM : public fxl::RefCountedThreadSafe { - public: - class PlatformKernel; - - static fxl::RefPtr ForProcess(Settings settings); - - static fxl::RefPtr ForProcess( - Settings settings, - fxl::RefPtr vm_snapshot, - fxl::RefPtr isolate_snapshot); - - static fxl::RefPtr ForProcessIfInitialized(); - - static bool IsRunningPrecompiledCode(); - - const Settings& GetSettings() const; - - PlatformKernel* GetPlatformKernel() const; - - const DartSnapshot& GetVMSnapshot() const; - - fxl::RefPtr GetIsolateSnapshot() const; - - fxl::WeakPtr GetWeakPtr(); - - ServiceProtocol& GetServiceProtocol(); - - private: - const Settings settings_; - const fxl::RefPtr vm_snapshot_; - const fxl::RefPtr isolate_snapshot_; - std::unique_ptr platform_kernel_mapping_; - PlatformKernel* platform_kernel_ = nullptr; - ServiceProtocol service_protocol_; - fxl::WeakPtrFactory weak_factory_; - - DartVM(const Settings& settings, - fxl::RefPtr vm_snapshot, - fxl::RefPtr isolate_snapshot); - - ~DartVM(); - - FRIEND_REF_COUNTED_THREAD_SAFE(DartVM); - FRIEND_MAKE_REF_COUNTED(DartVM); - FXL_DISALLOW_COPY_AND_ASSIGN(DartVM); -}; - -} // namespace blink - -#endif // FLUTTER_RUNTIME_DART_VM_H_ diff --git a/runtime/dart_vm_unittests.cc b/runtime/dart_vm_unittests.cc deleted file mode 100644 index 5b2f5e6ee8299..0000000000000 --- a/runtime/dart_vm_unittests.cc +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/runtime/dart_vm.h" -#include "gtest/gtest.h" - -namespace blink { - -TEST(DartVM, SimpleInitialization) { - Settings settings = {}; - settings.task_observer_add = [](intptr_t, fxl::Closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - auto vm = DartVM::ForProcess(settings); - ASSERT_TRUE(vm); - ASSERT_EQ(vm, DartVM::ForProcess(settings)); - ASSERT_FALSE(DartVM::IsRunningPrecompiledCode()); - ASSERT_EQ(vm->GetPlatformKernel(), nullptr); -} - -} // namespace blink diff --git a/runtime/fixtures/simple_main.dart b/runtime/fixtures/simple_main.dart deleted file mode 100644 index 552dfbe344902..0000000000000 --- a/runtime/fixtures/simple_main.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -void simple_main() { - print("Hello"); -} diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index d3e138c937f60..75796cd68697e 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -4,244 +4,192 @@ #include "flutter/runtime/runtime_controller.h" -#include "flutter/fml/message_loop.h" #include "flutter/glue/trace_event.h" #include "flutter/lib/ui/compositing/scene.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/window.h" +#include "flutter/runtime/dart_controller.h" #include "flutter/runtime/runtime_delegate.h" #include "lib/tonic/dart_message_handler.h" +using tonic::DartState; + namespace blink { -RuntimeController::RuntimeController( - RuntimeDelegate& p_client, - const DartVM* p_vm, - TaskRunners p_task_runners, - fml::WeakPtr p_resource_context, - fxl::RefPtr p_unref_queue) - : RuntimeController(p_client, - p_vm, - std::move(p_task_runners), - std::move(p_resource_context), - std::move(p_unref_queue), - WindowData{/* default window data */}) {} - -RuntimeController::RuntimeController( - RuntimeDelegate& p_client, - const DartVM* p_vm, - TaskRunners p_task_runners, - fml::WeakPtr p_resource_context, - fxl::RefPtr p_unref_queue, - WindowData p_window_data) - : client_(p_client), - vm_(p_vm), - task_runners_(p_task_runners), - resource_context_(p_resource_context), - unref_queue_(p_unref_queue), - window_data_(std::move(p_window_data)), - root_isolate_( - DartIsolate::CreateRootIsolate(vm_, - vm_->GetIsolateSnapshot(), - task_runners_, - std::make_unique(this), - resource_context_, - unref_queue_)) { - root_isolate_->SetReturnCodeCallback([this](uint32_t code) { - root_isolate_return_code_ = {true, code}; - }); - if (auto window = GetWindowIfAvailable()) { - tonic::DartState::Scope scope(root_isolate_.get()); - window->DidCreateIsolate(); - if (!FlushRuntimeStateToIsolate()) { - FXL_DLOG(ERROR) << "Could not setup intial isolate state."; - } - } else { - FXL_DCHECK(false) << "RuntimeController created without window binding."; - } - FXL_DCHECK(Dart_CurrentIsolate() == nullptr); -} - -RuntimeController::~RuntimeController() { - FXL_DCHECK(Dart_CurrentIsolate() == nullptr); - if (root_isolate_) { - root_isolate_->SetReturnCodeCallback(nullptr); - auto result = root_isolate_->Shutdown(); - if (!result) { - FXL_DLOG(ERROR) << "Could not shutdown the root isolate."; - } - root_isolate_ = {}; - } +std::unique_ptr RuntimeController::Create( + RuntimeDelegate* client) { + return std::unique_ptr(new RuntimeController(client)); } -std::unique_ptr RuntimeController::Clone() const { - return std::unique_ptr(new RuntimeController( - client_, // - vm_, // - task_runners_, // - resource_context_, // - unref_queue_, // - window_data_ // - )); -} +RuntimeController::RuntimeController(RuntimeDelegate* client) + : client_(client) {} -bool RuntimeController::FlushRuntimeStateToIsolate() { - return SetViewportMetrics(window_data_.viewport_metrics) && - SetLocale(window_data_.language_code, window_data_.country_code) && - SetSemanticsEnabled(window_data_.semantics_enabled); -} +RuntimeController::~RuntimeController() {} -bool RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { - window_data_.viewport_metrics = metrics; +void RuntimeController::CreateDartController( + const std::string& script_uri, + const uint8_t* isolate_snapshot_data, + const uint8_t* isolate_snapshot_instr, + int dirfd) { + FXL_DCHECK(!dart_controller_); - if (auto window = GetWindowIfAvailable()) { - window->UpdateWindowMetrics(metrics); - return true; - } - return false; -} + dart_controller_.reset(new DartController()); + dart_controller_->CreateIsolateFor( + script_uri, isolate_snapshot_data, isolate_snapshot_instr, + std::make_unique(this, std::make_unique(this), + dirfd)); -bool RuntimeController::SetLocale(const std::string& language_code, - const std::string& country_code) { - window_data_.language_code = language_code; - window_data_.country_code = country_code; + UIDartState* dart_state = dart_controller_->dart_state(); + DartState::Scope scope(dart_state); + dart_state->window()->DidCreateIsolate(); + client_->DidCreateMainIsolate(dart_state->isolate()); - if (auto window = GetWindowIfAvailable()) { - window->UpdateLocale(window_data_.language_code, window_data_.country_code); - return true; - } + Window* window = GetWindow(); + + window->UpdateLocale(language_code_, country_code_); - return false; + if (semantics_enabled_) + window->UpdateSemanticsEnabled(semantics_enabled_); } -bool RuntimeController::SetUserSettingsData(const std::string& data) { - window_data_.user_settings_data = data; +void RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { + GetWindow()->UpdateWindowMetrics(metrics); +} - if (auto window = GetWindowIfAvailable()) { - window->UpdateUserSettingsData(window_data_.user_settings_data); - return true; - } +void RuntimeController::SetLocale(const std::string& language_code, + const std::string& country_code) { + if (language_code_ == language_code && country_code_ == country_code) + return; - return false; + language_code_ = language_code; + country_code_ = country_code; + GetWindow()->UpdateLocale(language_code_, country_code_); } -bool RuntimeController::SetSemanticsEnabled(bool enabled) { - window_data_.semantics_enabled = enabled; - - if (auto window = GetWindowIfAvailable()) { - window->UpdateSemanticsEnabled(window_data_.semantics_enabled); - return true; - } +void RuntimeController::SetUserSettingsData(const std::string& data) { + if (user_settings_data_ == data) + return; + user_settings_data_ = data; + GetWindow()->UpdateUserSettingsData(user_settings_data_); +} - return false; +void RuntimeController::SetSemanticsEnabled(bool enabled) { + if (semantics_enabled_ == enabled) + return; + semantics_enabled_ = enabled; + GetWindow()->UpdateSemanticsEnabled(semantics_enabled_); } -bool RuntimeController::BeginFrame(fxl::TimePoint frame_time) { - if (auto window = GetWindowIfAvailable()) { - window->BeginFrame(frame_time); - return true; - } - return false; +void RuntimeController::BeginFrame(fxl::TimePoint frame_time) { + GetWindow()->BeginFrame(frame_time); } -bool RuntimeController::NotifyIdle(int64_t deadline) { - if (!root_isolate_) { - return false; +void RuntimeController::NotifyIdle(int64_t deadline) { + UIDartState* dart_state = dart_controller_->dart_state(); + if (!dart_state) { + return; } - - tonic::DartState::Scope scope(root_isolate_.get()); + DartState::Scope scope(dart_state); Dart_NotifyIdle(deadline); - return true; } -bool RuntimeController::DispatchPlatformMessage( +void RuntimeController::DispatchPlatformMessage( fxl::RefPtr message) { - if (auto window = GetWindowIfAvailable()) { - TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", - "mode", "basic"); - window->DispatchPlatformMessage(std::move(message)); - return true; - } - return false; + TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", "mode", + "basic"); + GetWindow()->DispatchPlatformMessage(std::move(message)); } -bool RuntimeController::DispatchPointerDataPacket( +void RuntimeController::DispatchPointerDataPacket( const PointerDataPacket& packet) { - if (auto window = GetWindowIfAvailable()) { - TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", - "mode", "basic"); - window->DispatchPointerDataPacket(packet); - return true; - } - return false; + TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", + "mode", "basic"); + GetWindow()->DispatchPointerDataPacket(packet); } -bool RuntimeController::DispatchSemanticsAction(int32_t id, +void RuntimeController::DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector args) { TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode", "basic"); - if (auto window = GetWindowIfAvailable()) { - window->DispatchSemanticsAction(id, action, std::move(args)); - return true; - } - return false; + GetWindow()->DispatchSemanticsAction(id, action, std::move(args)); } -Window* RuntimeController::GetWindowIfAvailable() { - return root_isolate_ ? root_isolate_->window() : nullptr; +Window* RuntimeController::GetWindow() { + return dart_controller_->dart_state()->window(); } std::string RuntimeController::DefaultRouteName() { - return client_.DefaultRouteName(); + return client_->DefaultRouteName(); } void RuntimeController::ScheduleFrame() { - client_.ScheduleFrame(); + client_->ScheduleFrame(); } void RuntimeController::Render(Scene* scene) { - client_.Render(scene->takeLayerTree()); + client_->Render(scene->takeLayerTree()); } void RuntimeController::UpdateSemantics(SemanticsUpdate* update) { - if (window_data_.semantics_enabled) { - client_.UpdateSemantics(update->takeNodes()); - } + if (semantics_enabled_) + client_->UpdateSemantics(update->takeNodes()); } void RuntimeController::HandlePlatformMessage( fxl::RefPtr message) { - client_.HandlePlatformMessage(std::move(message)); + client_->HandlePlatformMessage(std::move(message)); +} + +void RuntimeController::DidCreateSecondaryIsolate(Dart_Isolate isolate) { + client_->DidCreateSecondaryIsolate(isolate); +} + +void RuntimeController::DidShutdownMainIsolate() { + client_->DidShutdownMainIsolate(); } Dart_Port RuntimeController::GetMainPort() { - return root_isolate_ ? root_isolate_->main_port() : ILLEGAL_PORT; + if (!dart_controller_) { + return ILLEGAL_PORT; + } + if (!dart_controller_->dart_state()) { + return ILLEGAL_PORT; + } + return dart_controller_->dart_state()->main_port(); } std::string RuntimeController::GetIsolateName() { - return root_isolate_ ? root_isolate_->debug_name() : ""; + if (!dart_controller_) { + return ""; + } + if (!dart_controller_->dart_state()) { + return ""; + } + return dart_controller_->dart_state()->debug_name(); } bool RuntimeController::HasLivePorts() { - if (!root_isolate_) { + if (!dart_controller_) { return false; } - tonic::DartState::Scope scope(root_isolate_.get()); + UIDartState* dart_state = dart_controller_->dart_state(); + if (!dart_state) { + return false; + } + DartState::Scope scope(dart_state); return Dart_HasLivePorts(); } tonic::DartErrorHandleType RuntimeController::GetLastError() { - return root_isolate_ ? root_isolate_->message_handler().isolate_last_error() - : tonic::kNoError; -} - -fml::WeakPtr RuntimeController::GetRootIsolate() { - return root_isolate_; -} - -std::pair RuntimeController::GetRootIsolateReturnCode() { - return root_isolate_return_code_; + if (!dart_controller_) { + return tonic::kNoError; + } + UIDartState* dart_state = dart_controller_->dart_state(); + if (!dart_state) { + return tonic::kNoError; + } + return dart_state->message_handler().isolate_last_error(); } } // namespace blink diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 326c517f31db2..628bc699395c0 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -7,109 +7,72 @@ #include -#include "flutter/common/task_runners.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/pointer_data_packet.h" #include "flutter/lib/ui/window/window.h" -#include "flutter/runtime/dart_vm.h" #include "lib/fxl/macros.h" namespace blink { +class DartController; +class DartLibraryProvider; class Scene; class RuntimeDelegate; class View; class Window; -class RuntimeController final : public WindowClient { +class RuntimeController : public WindowClient, public IsolateClient { public: - RuntimeController(RuntimeDelegate& client, - const DartVM* vm, - TaskRunners task_runners, - fml::WeakPtr resource_context, - fxl::RefPtr unref_queue); - + static std::unique_ptr Create(RuntimeDelegate* client); ~RuntimeController(); - std::unique_ptr Clone() const; - - bool SetViewportMetrics(const ViewportMetrics& metrics); + void CreateDartController(const std::string& script_uri, + const uint8_t* isolate_snapshot_data, + const uint8_t* isolate_snapshot_instr, + int dirfd = -1); + DartController* dart_controller() const { return dart_controller_.get(); } - bool SetLocale(const std::string& language_code, + void SetViewportMetrics(const ViewportMetrics& metrics); + void SetLocale(const std::string& language_code, const std::string& country_code); + void SetUserSettingsData(const std::string& data); + void SetSemanticsEnabled(bool enabled); - bool SetUserSettingsData(const std::string& data); - - bool SetSemanticsEnabled(bool enabled); - - bool BeginFrame(fxl::TimePoint frame_time); - - bool NotifyIdle(int64_t deadline); + void BeginFrame(fxl::TimePoint frame_time); + void NotifyIdle(int64_t deadline); - bool DispatchPlatformMessage(fxl::RefPtr message); - - bool DispatchPointerDataPacket(const PointerDataPacket& packet); - - bool DispatchSemanticsAction(int32_t id, + void DispatchPlatformMessage(fxl::RefPtr message); + void DispatchPointerDataPacket(const PointerDataPacket& packet); + void DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector args); Dart_Port GetMainPort(); - std::string GetIsolateName(); - bool HasLivePorts(); - tonic::DartErrorHandleType GetLastError(); - fml::WeakPtr GetRootIsolate(); + private: + explicit RuntimeController(RuntimeDelegate* client); - std::pair GetRootIsolateReturnCode(); + Window* GetWindow(); - private: - struct WindowData { - ViewportMetrics viewport_metrics; - std::string language_code; - std::string country_code; - std::string user_settings_data = "{}"; - bool semantics_enabled = false; - }; - - RuntimeDelegate& client_; - const DartVM* vm_; - TaskRunners task_runners_; - fml::WeakPtr resource_context_; - fxl::RefPtr unref_queue_; - WindowData window_data_; - fml::WeakPtr root_isolate_; - std::pair root_isolate_return_code_ = {false, 0}; - - RuntimeController(RuntimeDelegate& client, - const DartVM* vm, - TaskRunners task_runners, - fml::WeakPtr resource_context, - fxl::RefPtr unref_queue, - WindowData data); - - Window* GetWindowIfAvailable(); - - bool FlushRuntimeStateToIsolate(); - - // |blink::WindowClient| std::string DefaultRouteName() override; - - // |blink::WindowClient| void ScheduleFrame() override; - - // |blink::WindowClient| void Render(Scene* scene) override; - - // |blink::WindowClient| void UpdateSemantics(SemanticsUpdate* update) override; - - // |blink::WindowClient| void HandlePlatformMessage(fxl::RefPtr message) override; + void DidCreateSecondaryIsolate(Dart_Isolate isolate) override; + void DidShutdownMainIsolate() override; + + RuntimeDelegate* client_; + std::string language_code_; + std::string country_code_; + std::string user_settings_data_ = "{}"; + bool semantics_enabled_ = false; + std::unique_ptr dart_controller_; + FXL_DISALLOW_COPY_AND_ASSIGN(RuntimeController); }; diff --git a/runtime/runtime_delegate.cc b/runtime/runtime_delegate.cc index 902672be06d8f..6ec55c4c2e6a0 100644 --- a/runtime/runtime_delegate.cc +++ b/runtime/runtime_delegate.cc @@ -6,6 +6,12 @@ namespace blink { -RuntimeDelegate::~RuntimeDelegate() = default; +RuntimeDelegate::~RuntimeDelegate() {} + +void RuntimeDelegate::DidCreateMainIsolate(Dart_Isolate isolate) {} + +void RuntimeDelegate::DidCreateSecondaryIsolate(Dart_Isolate isolate) {} + +void RuntimeDelegate::DidShutdownMainIsolate() {} } // namespace blink diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index c6d6c0a92b2b4..36650fe7fb70b 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -18,15 +18,15 @@ namespace blink { class RuntimeDelegate { public: virtual std::string DefaultRouteName() = 0; - virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0; - virtual void Render(std::unique_ptr layer_tree) = 0; - virtual void UpdateSemantics(blink::SemanticsNodeUpdates update) = 0; - virtual void HandlePlatformMessage(fxl::RefPtr message) = 0; + virtual void DidCreateMainIsolate(Dart_Isolate isolate); + virtual void DidCreateSecondaryIsolate(Dart_Isolate isolate); + virtual void DidShutdownMainIsolate(); + protected: virtual ~RuntimeDelegate(); }; diff --git a/runtime/runtime_init.cc b/runtime/runtime_init.cc new file mode 100644 index 0000000000000..eda66e5495aed --- /dev/null +++ b/runtime/runtime_init.cc @@ -0,0 +1,35 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/runtime/runtime_init.h" + +#include "flutter/glue/trace_event.h" +#include "flutter/runtime/dart_init.h" +#include "flutter/runtime/platform_impl.h" +#include "flutter/sky/engine/public/web/Sky.h" +#include "lib/fxl/logging.h" + +namespace blink { +namespace { + +PlatformImpl* g_platform_impl = nullptr; + +} // namespace + +void InitRuntime(const uint8_t* vm_snapshot_data, + const uint8_t* vm_snapshot_instructions, + const uint8_t* default_isolate_snapshot_data, + const uint8_t* default_isolate_snapshot_instructions, + const std::string& bundle_path) { + TRACE_EVENT0("flutter", "InitRuntime"); + + FXL_CHECK(!g_platform_impl); + g_platform_impl = new PlatformImpl(); + InitEngine(g_platform_impl); + InitDartVM(vm_snapshot_data, vm_snapshot_instructions, + default_isolate_snapshot_data, + default_isolate_snapshot_instructions, bundle_path); +} + +} // namespace blink diff --git a/runtime/runtime_init.h b/runtime/runtime_init.h new file mode 100644 index 0000000000000..515ae284e3460 --- /dev/null +++ b/runtime/runtime_init.h @@ -0,0 +1,21 @@ +// Copyright 2016 The Chromium 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_RUNTIME_RUNTIME_INIT_H_ +#define FLUTTER_RUNTIME_RUNTIME_INIT_H_ + +#include +#include + +namespace blink { + +void InitRuntime(const uint8_t* vm_snapshot_data, + const uint8_t* vm_snapshot_instructions, + const uint8_t* default_isolate_snapshot_data, + const uint8_t* default_isolate_snapshot_instructions, + const std::string& bundle_path); + +} // namespace blink + +#endif // FLUTTER_RUNTIME_RUNTIME_INIT_H_ diff --git a/runtime/service_protocol.cc b/runtime/service_protocol.cc deleted file mode 100644 index 030901e54269d..0000000000000 --- a/runtime/service_protocol.cc +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2017 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. - -#define RAPIDJSON_HAS_STDSTRING 1 - -#include "flutter/runtime/service_protocol.h" - -#include - -#include -#include -#include -#include - -#include "lib/fxl/synchronization/waitable_event.h" -#include "rapidjson/stringbuffer.h" -#include "rapidjson/writer.h" -#include "third_party/dart/runtime/include/dart_tools_api.h" - -namespace blink { - -const fxl::StringView ServiceProtocol::kScreenshotExtensionName = - "_flutter.screenshot"; -const fxl::StringView ServiceProtocol::kScreenshotSkpExtensionName = - "_flutter.screenshotSkp"; -const fxl::StringView ServiceProtocol::kRunInViewExtensionName = - "_flutter.runInView"; -const fxl::StringView ServiceProtocol::kFlushUIThreadTasksExtensionName = - "_flutter.flushUIThreadTasks"; -const fxl::StringView ServiceProtocol::kSetAssetBundlePathExtensionName = - "_flutter.setAssetBundlePath"; - -static constexpr fxl::StringView kViewIdPrefx = "_flutterView/"; -static constexpr fxl::StringView kListViewsExtensionName = "_flutter.listViews"; - -ServiceProtocol::ServiceProtocol() - : endpoints_({ - // Private - kListViewsExtensionName, - - // Public - kScreenshotExtensionName, - kScreenshotSkpExtensionName, - kRunInViewExtensionName, - kFlushUIThreadTasksExtensionName, - kSetAssetBundlePathExtensionName, - }) {} - -ServiceProtocol::~ServiceProtocol() { - ToggleHooks(false); -} - -void ServiceProtocol::AddHandler(Handler* handler) { - std::lock_guard lock(handlers_mutex_); - handlers_.emplace(handler); -} - -void ServiceProtocol::RemoveHandler(Handler* handler) { - std::lock_guard lock(handlers_mutex_); - handlers_.erase(handler); -} - -void ServiceProtocol::ToggleHooks(bool set) { - for (const auto& endpoint : endpoints_) { - Dart_RegisterRootServiceRequestCallback( - endpoint.data(), // method - &ServiceProtocol::HandleMessage, // callback - set ? this : nullptr // user data - ); - } -} - -static void WriteServerErrorResponse(rapidjson::Document& document, - const char* message) { - document.SetObject(); - document.AddMember("code", -32000, document.GetAllocator()); - rapidjson::Value message_value; - message_value.SetString(message, document.GetAllocator()); - document.AddMember("message", message_value, document.GetAllocator()); -} - -bool ServiceProtocol::HandleMessage(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object) { - Handler::ServiceProtocolMap params; - for (intptr_t i = 0; i < num_params; i++) { - params[fxl::StringView{param_keys[i]}] = fxl::StringView{param_values[i]}; - } - -#ifndef NDEBUG - FXL_DLOG(INFO) << "Service protcol method: " << method; - FXL_DLOG(INFO) << "Arguments: " << params.size(); - for (intptr_t i = 0; i < num_params; i++) { - FXL_DLOG(INFO) << " " << i + 1 << ": " << param_keys[i] << " = " - << param_values[i]; - } -#endif // NDEBUG - - rapidjson::Document document; - bool result = HandleMessage(fxl::StringView{method}, // - params, // - static_cast(user_data), // - document // - ); - rapidjson::StringBuffer buffer; - rapidjson::Writer writer(buffer); - document.Accept(writer); - *json_object = strdup(buffer.GetString()); - -#ifndef NDEBUG - FXL_DLOG(INFO) << "Response: " << *json_object; - FXL_DLOG(INFO) << "RPC Result: " << result; -#endif // NDEBUG - - return result; -} - -bool ServiceProtocol::HandleMessage(fxl::StringView method, - const Handler::ServiceProtocolMap& params, - ServiceProtocol* service_protocol, - rapidjson::Document& response) { - if (service_protocol == nullptr) { - WriteServerErrorResponse(response, "Service protocol unavailable."); - return false; - } - - return service_protocol->HandleMessage(method, params, response); -} - -FXL_WARN_UNUSED_RESULT -static bool HandleMessageOnHandler( - ServiceProtocol::Handler* handler, - fxl::StringView method, - const ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& document) { - FXL_DCHECK(handler); - fxl::AutoResetWaitableEvent latch; - bool result = false; - fml::TaskRunner::RunNowOrPostTask( - handler->GetServiceProtocolHandlerTaskRunner(method), - [&latch, // - &result, // - &handler, // - &method, // - ¶ms, // - &document // - ]() { - result = - handler->HandleServiceProtocolMessage(method, params, document); - latch.Signal(); - }); - latch.Wait(); - return result; -} - -bool ServiceProtocol::HandleMessage(fxl::StringView method, - const Handler::ServiceProtocolMap& params, - rapidjson::Document& response) const { - if (method == kListViewsExtensionName) { - // So far, this is the only built-in method that does not forward to the - // dynamic set of handlers. - return HandleListViewsMethod(response); - } - - std::lock_guard lock(handlers_mutex_); - - if (handlers_.size() == 0) { - WriteServerErrorResponse(response, - "There are no running service protocol handlers."); - return false; - } - - // Find the handler by its "viewId" in the params. - auto view_id_param_found = params.find(fxl::StringView{"viewId"}); - if (view_id_param_found != params.end()) { - auto handler = reinterpret_cast(std::stoull( - view_id_param_found->second.data() + kViewIdPrefx.size(), nullptr, 16)); - auto handler_found = handlers_.find(handler); - if (handler_found != handlers_.end()) { - return HandleMessageOnHandler(handler, method, params, response); - } - } - - // Handle legacy calls that do not specify a handler in their args. - // TODO(chinmaygarde): Deprecate these calls in the tools and remove these - // fallbacks. - if (method == kScreenshotExtensionName || - method == kScreenshotSkpExtensionName) { - return HandleMessageOnHandler(*handlers_.begin(), method, params, response); - } - - WriteServerErrorResponse( - response, - "Service protocol could not handle or find a handler for the " - "requested method."); - return false; -} - -static std::string CreateFlutterViewID(intptr_t handler) { - std::stringstream stream; - stream << kViewIdPrefx << "0x" << std::hex << handler; - return stream.str(); -} - -static std::string CreateIsolateID(int64_t isolate) { - std::stringstream stream; - stream << "isolates/" << isolate; - return stream.str(); -} - -void ServiceProtocol::Handler::Description::Write( - Handler* handler, - rapidjson::Value& view, - rapidjson::MemoryPoolAllocator<>& allocator) const { - view.SetObject(); - view.AddMember("type", "FlutterView", allocator); - view.AddMember("id", CreateFlutterViewID(reinterpret_cast(handler)), - allocator); - if (isolate_port != 0) { - rapidjson::Value isolate(rapidjson::Type::kObjectType); - { - isolate.AddMember("type", "@Isolate", allocator); - isolate.AddMember("fixedId", true, allocator); - isolate.AddMember("id", CreateIsolateID(isolate_port), allocator); - isolate.AddMember("name", isolate_name, allocator); - isolate.AddMember("number", isolate_port, allocator); - } - view.AddMember("isolate", isolate, allocator); - } -} - -bool ServiceProtocol::HandleListViewsMethod( - rapidjson::Document& response) const { - // Collect handler descriptions on their respective task runners. - std::lock_guard lock(handlers_mutex_); - std::vector> descriptions; - for (const auto& handler : handlers_) { - fxl::AutoResetWaitableEvent latch; - Handler::Description description; - - fml::TaskRunner::RunNowOrPostTask( - handler->GetServiceProtocolHandlerTaskRunner( - kListViewsExtensionName), // task runner - [&latch, // - &description, // - &handler // - ]() { - description = handler->GetServiceProtocolDescription(); - latch.Signal(); - }); - latch.Wait(); - descriptions.emplace_back(std::make_pair( - reinterpret_cast(handler), std::move(description))); - } - - auto& allocator = response.GetAllocator(); - - // Construct the response objects. - response.SetObject(); - response.AddMember("type", "FlutterViewList", allocator); - - rapidjson::Value viewsList(rapidjson::Type::kArrayType); - for (const auto& description : descriptions) { - rapidjson::Value view(rapidjson::Type::kObjectType); - description.second.Write(reinterpret_cast(description.first), - view, allocator); - viewsList.PushBack(view, allocator); - } - - response.AddMember("views", viewsList, allocator); - - return true; -} - -} // namespace blink diff --git a/runtime/service_protocol.h b/runtime/service_protocol.h deleted file mode 100644 index 056f7389ea79a..0000000000000 --- a/runtime/service_protocol.h +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2017 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_RUNTIME_SERVICE_PROTOCOL_H_ -#define FLUTTER_RUNTIME_SERVICE_PROTOCOL_H_ - -#include -#include -#include -#include - -#include "flutter/fml/task_runner.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/strings/string_view.h" -#include "lib/fxl/synchronization/thread_annotations.h" -#include "third_party/rapidjson/rapidjson/document.h" - -namespace blink { - -class ServiceProtocol { - public: - static const fxl::StringView kScreenshotExtensionName; - static const fxl::StringView kScreenshotSkpExtensionName; - static const fxl::StringView kRunInViewExtensionName; - static const fxl::StringView kFlushUIThreadTasksExtensionName; - static const fxl::StringView kSetAssetBundlePathExtensionName; - - class Handler { - public: - struct Description { - int64_t isolate_port = 0 /* illegal port by default. */; - std::string isolate_name; - - Description() {} - - Description(int64_t p_isolate_port, std::string p_isolate_name) - : isolate_port(p_isolate_port), - isolate_name(std::move(p_isolate_name)) {} - - void Write(Handler* handler, - rapidjson::Value& value, - rapidjson::MemoryPoolAllocator<>& allocator) const; - }; - - using ServiceProtocolMap = std::map; - - virtual fxl::RefPtr GetServiceProtocolHandlerTaskRunner( - fxl::StringView method) const = 0; - - virtual Description GetServiceProtocolDescription() const = 0; - - virtual bool HandleServiceProtocolMessage( - fxl::StringView method, // one if the extension names specified above. - const ServiceProtocolMap& params, - rapidjson::Document& response) = 0; - }; - - ServiceProtocol(); - - ~ServiceProtocol(); - - void ToggleHooks(bool set); - - void AddHandler(Handler* handler); - - void RemoveHandler(Handler* handler); - - private: - const std::set endpoints_; - mutable std::mutex handlers_mutex_; - std::set handlers_; - - FXL_WARN_UNUSED_RESULT - static bool HandleMessage(const char* method, - const char** param_keys, - const char** param_values, - intptr_t num_params, - void* user_data, - const char** json_object); - FXL_WARN_UNUSED_RESULT - static bool HandleMessage(fxl::StringView method, - const Handler::ServiceProtocolMap& params, - ServiceProtocol* service_protocol, - rapidjson::Document& response); - FXL_WARN_UNUSED_RESULT - bool HandleMessage(fxl::StringView method, - const Handler::ServiceProtocolMap& params, - rapidjson::Document& response) const; - - FXL_WARN_UNUSED_RESULT - bool HandleListViewsMethod(rapidjson::Document& response) const; - - FXL_DISALLOW_COPY_AND_ASSIGN(ServiceProtocol); -}; - -} // namespace blink - -#endif // FLUTTER_RUNTIME_SERVICE_PROTOCOL_H_ diff --git a/shell/common/BUILD.gn b/shell/common/BUILD.gn index 25edcfa23bd85..f9e25a3c8d6d7 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -2,8 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("$flutter_root/testing/testing.gni") - # Template to generate a dart embedder resource.cc file. # Required invoker inputs: # String output (name of output file) @@ -63,18 +61,18 @@ source_set("common") { "animator.h", "engine.cc", "engine.h", - "io_manager.cc", - "io_manager.h", - "isolate_configuration.cc", - "isolate_configuration.h", + "null_platform_view.cc", + "null_platform_view.h", + "null_rasterizer.cc", + "null_rasterizer.h", "picture_serializer.cc", "picture_serializer.h", "platform_view.cc", "platform_view.h", + "platform_view_service_protocol.cc", + "platform_view_service_protocol.h", "rasterizer.cc", "rasterizer.h", - "run_configuration.cc", - "run_configuration.h", "shell.cc", "shell.h", "skia_event_tracer_impl.cc", @@ -83,8 +81,8 @@ source_set("common") { "surface.h", "switches.cc", "switches.h", - "thread_host.cc", - "thread_host.h", + "tracing_controller.cc", + "tracing_controller.h", "vsync_waiter.cc", "vsync_waiter.h", "vsync_waiter_fallback.cc", @@ -92,6 +90,8 @@ source_set("common") { ] deps = [ + "//third_party/dart/runtime:dart_api", + "//third_party/dart/runtime/platform:libdart_platform", "$flutter_root/assets", "$flutter_root/common", "$flutter_root/flow", @@ -99,13 +99,10 @@ source_set("common") { "$flutter_root/glue", "$flutter_root/lib/ui", "$flutter_root/runtime", - "$flutter_root/sky/engine/platform", "$flutter_root/sky/engine/wtf", "$flutter_root/synchronization", "$flutter_root/third_party/txt", "//garnet/public/lib/fxl", - "//third_party/dart/runtime:dart_api", - "//third_party/dart/runtime/platform:libdart_platform", "//third_party/rapidjson", "//third_party/skia", "//third_party/skia:gpu", @@ -115,23 +112,7 @@ source_set("common") { "//topaz/lib/tonic", ] - public_configs = [ "$flutter_root:config" ] -} - -executable("shell_unittests") { - testonly = true - - sources = [ - "shell_unittests.cc", - ] - deps = [ - ":common", - "$flutter_root/fml", - "$flutter_root/lib/snapshot", - "$flutter_root/testing", - "//garnet/public/lib/fxl", - "//third_party/dart/runtime:libdart_jit", - "//third_party/skia", - "//topaz/lib/tonic", + public_configs = [ + "$flutter_root:config", ] } diff --git a/shell/common/animator.cc b/shell/common/animator.cc index 60177a18f89ab..d5679a0160a86 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -4,18 +4,19 @@ #include "flutter/shell/common/animator.h" -#include "flutter/glue/trace_event.h" +#include "flutter/common/threads.h" +#include "flutter/fml/trace_event.h" #include "lib/fxl/time/stopwatch.h" #include "third_party/dart/runtime/include/dart_tools_api.h" namespace shell { -Animator::Animator(Delegate& delegate, - blink::TaskRunners task_runners, - std::unique_ptr waiter) - : delegate_(delegate), - task_runners_(std::move(task_runners)), - waiter_(std::move(waiter)), +Animator::Animator(fml::WeakPtr rasterizer, + VsyncWaiter* waiter, + Engine* engine) + : rasterizer_(rasterizer), + waiter_(waiter), + engine_(engine), last_begin_frame_time_(), dart_frame_deadline_(0), layer_tree_pipeline_(fxl::MakeRefCounted(2)), @@ -78,6 +79,7 @@ void Animator::BeginFrame(fxl::TimePoint frame_start_time, // If we still don't have valid continuation, the pipeline is currently // full because the consumer is being too slow. Try again at the next // frame interval. + TRACE_EVENT_INSTANT0("flutter", "ConsumerSlowDefer"); RequestFrame(); return; } @@ -92,13 +94,13 @@ void Animator::BeginFrame(fxl::TimePoint frame_start_time, { TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame", FrameParity()); - delegate_.OnAnimatorBeginFrame(*this, last_begin_frame_time_); + engine_->BeginFrame(last_begin_frame_time_); } if (!frame_scheduled_) { // We don't have another frame pending, so we're waiting on user input // or I/O. Allow the Dart VM 100 ms. - delegate_.OnAnimatorNotifyIdle(*this, dart_frame_deadline_ + 100000); + engine_->NotifyIdle(dart_frame_deadline_ + 100000); } } @@ -118,7 +120,15 @@ void Animator::Render(std::unique_ptr layer_tree) { // Commit the pending continuation. producer_continuation_.Complete(std::move(layer_tree)); - delegate_.OnAnimatorDraw(*this, layer_tree_pipeline_); + blink::Threads::Gpu()->PostTask([ + rasterizer = rasterizer_, pipeline = layer_tree_pipeline_, + frame_id = FrameParity() + ]() { + if (!rasterizer.get()) + return; + TRACE_EVENT2("flutter", "GPU Workload", "mode", "basic", "frame", frame_id); + rasterizer->Draw(pipeline); + }); } bool Animator::CanReuseLastLayerTree() { @@ -127,7 +137,10 @@ bool Animator::CanReuseLastLayerTree() { void Animator::DrawLastLayerTree() { pending_frame_semaphore_.Signal(); - delegate_.OnAnimatorDrawLastLayerTree(*this); + blink::Threads::Gpu()->PostTask([rasterizer = rasterizer_]() { + if (rasterizer.get()) + rasterizer->DrawLastLayerTree(); + }); } void Animator::RequestFrame(bool regenerate_layer_tree) { @@ -151,31 +164,31 @@ void Animator::RequestFrame(bool regenerate_layer_tree) { // started an expensive operation right after posting this message however. // To support that, we need edge triggered wakes on VSync. - task_runners_.GetUITaskRunner()->PostTask([self = weak_factory_.GetWeakPtr(), - frame_number = frame_number_]() { - if (!self.get()) { - return; - } - TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", frame_number); - self->AwaitVSync(); - }); + blink::Threads::UI()->PostTask( + [ self = weak_factory_.GetWeakPtr(), frame_number = frame_number_ ]() { + if (!self.get()) { + return; + } + TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", + frame_number); + self->AwaitVSync(); + }); frame_scheduled_ = true; } void Animator::AwaitVSync() { - waiter_->AsyncWaitForVsync( - [self = weak_factory_.GetWeakPtr()](fxl::TimePoint frame_start_time, - fxl::TimePoint frame_target_time) { - if (self) { - if (self->CanReuseLastLayerTree()) { - self->DrawLastLayerTree(); - } else { - self->BeginFrame(frame_start_time, frame_target_time); - } - } - }); + waiter_->AsyncWaitForVsync([self = weak_factory_.GetWeakPtr()]( + fxl::TimePoint frame_start_time, fxl::TimePoint frame_target_time) { + if (self) { + if (self->CanReuseLastLayerTree()) { + self->DrawLastLayerTree(); + } else { + self->BeginFrame(frame_start_time, frame_target_time); + } + } + }); - delegate_.OnAnimatorNotifyIdle(*this, dart_frame_deadline_); + engine_->NotifyIdle(dart_frame_deadline_); } } // namespace shell diff --git a/shell/common/animator.h b/shell/common/animator.h index 53b2ac6884158..bc2ee21441b29 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -5,7 +5,7 @@ #ifndef FLUTTER_SHELL_COMMON_ANIMATOR_H_ #define FLUTTER_SHELL_COMMON_ANIMATOR_H_ -#include "flutter/common/task_runners.h" +#include "flutter/shell/common/engine.h" #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/vsync_waiter.h" #include "flutter/synchronization/pipeline.h" @@ -16,29 +16,18 @@ namespace shell { -class Animator final { +class Animator { public: - class Delegate { - public: - virtual void OnAnimatorBeginFrame(const Animator& animator, - fxl::TimePoint frame_time) = 0; - - virtual void OnAnimatorNotifyIdle(const Animator& animator, - int64_t deadline) = 0; - - virtual void OnAnimatorDraw( - const Animator& animator, - fxl::RefPtr> pipeline) = 0; - - virtual void OnAnimatorDrawLastLayerTree(const Animator& animator) = 0; - }; - - Animator(Delegate& delegate, - blink::TaskRunners task_runners, - std::unique_ptr waiter); + Animator(fml::WeakPtr rasterizer, + VsyncWaiter* waiter, + Engine* engine); ~Animator(); + void set_rasterizer(fml::WeakPtr rasterizer) { + rasterizer_ = rasterizer; + } + void RequestFrame(bool regenerate_layer_tree = true); void Render(std::unique_ptr layer_tree); @@ -62,9 +51,9 @@ class Animator final { const char* FrameParity(); - Delegate& delegate_; - blink::TaskRunners task_runners_; - std::unique_ptr waiter_; + fml::WeakPtr rasterizer_; + VsyncWaiter* waiter_; + Engine* engine_; fxl::TimePoint last_begin_frame_time_; int64_t dart_frame_deadline_; @@ -78,7 +67,7 @@ class Animator final { bool dimension_change_pending_; SkISize last_layer_tree_size_; - fxl::WeakPtrFactory weak_factory_; + fml::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(Animator); }; diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 3d6fd496d3fa9..3629b729c29f7 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -4,20 +4,47 @@ #include "flutter/shell/common/engine.h" +#if OS(WIN) +#include +#include +#define access _access +#define R_OK 0x4 + +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode)&S_IFMT) == S_IFDIR) +#endif + +#ifndef S_ISREG +#define S_ISREG(mode) (((mode)&S_IFMT) == S_IFREG) +#endif + +#else +#include +#include +#include +#endif // OS(WIN) + +#include +#include #include #include +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/assets/unzipper_provider.h" +#include "flutter/assets/zip_asset_store.h" +#include "flutter/assets/asset_provider.h" #include "flutter/common/settings.h" +#include "flutter/common/threads.h" #include "flutter/glue/trace_event.h" #include "flutter/lib/snapshot/snapshot.h" #include "flutter/lib/ui/text/font_collection.h" #include "flutter/runtime/asset_font_selector.h" -#include "flutter/runtime/platform_impl.h" +#include "flutter/runtime/dart_controller.h" +#include "flutter/runtime/dart_init.h" +#include "flutter/runtime/runtime_init.h" #include "flutter/runtime/test_font_selector.h" #include "flutter/shell/common/animator.h" #include "flutter/shell/common/platform_view.h" -#include "flutter/shell/common/shell.h" -#include "flutter/sky/engine/platform/fonts/FontFallbackList.h" #include "flutter/sky/engine/public/web/Sky.h" #include "lib/fxl/files/eintr_wrapper.h" #include "lib/fxl/files/file.h" @@ -28,208 +55,380 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" -#ifdef ERROR -#undef ERROR +namespace shell { +namespace { + +constexpr char kAssetChannel[] = "flutter/assets"; +constexpr char kLifecycleChannel[] = "flutter/lifecycle"; +constexpr char kNavigationChannel[] = "flutter/navigation"; +constexpr char kLocalizationChannel[] = "flutter/localization"; +constexpr char kSettingsChannel[] = "flutter/settings"; + +#if OS(WIN) +void FindAndReplaceInPlace(std::string& str, + const std::string& findStr, + const std::string& replaceStr) { + size_t pos = 0; + while ((pos = str.find(findStr, pos)) != std::string::npos) { + str.replace(pos, findStr.length(), replaceStr); + pos += replaceStr.length(); + } +} #endif -namespace shell { +std::string SanitizePath(const std::string& path) { +#if OS(WIN) + std::string sanitized = path; + FindAndReplaceInPlace(sanitized, "\\\\", "/"); + if ((sanitized.length() > 2) && (sanitized[1] == ':')) { + // Path begins with a drive letter. + sanitized = '/' + sanitized; + } + return sanitized; +#else + return path; +#endif +} -static constexpr char kAssetChannel[] = "flutter/assets"; -static constexpr char kLifecycleChannel[] = "flutter/lifecycle"; -static constexpr char kNavigationChannel[] = "flutter/navigation"; -static constexpr char kLocalizationChannel[] = "flutter/localization"; -static constexpr char kSettingsChannel[] = "flutter/settings"; - -Engine::Engine(Delegate& delegate, - const blink::DartVM& vm, - blink::TaskRunners task_runners, - blink::Settings settings, - std::unique_ptr animator, - fml::WeakPtr resource_context, - fxl::RefPtr unref_queue) - : delegate_(delegate), - settings_(std::move(settings)), - animator_(std::move(animator)), - legacy_sky_platform_(settings_.using_blink ? new blink::PlatformImpl() - : nullptr), - load_script_error_(tonic::kNoError), - activity_running_(false), - have_surface_(false), - weak_factory_(this) { - weak_prototype_ = weak_factory_.GetWeakPtr(); +bool PathExists(const std::string& path) { + return access(path.c_str(), R_OK) == 0; +} - if (legacy_sky_platform_) { - // TODO: Remove this legacy call along with the platform. This is what makes - // the engine unable to run from multiple threads in the legacy - // configuration. - blink::InitEngine(legacy_sky_platform_.get()); +std::string FindPackagesPath(const std::string& main_dart) { + std::string directory = files::GetDirectoryName(main_dart); + std::string packages_path = directory + "/.packages"; + if (!PathExists(packages_path)) { + directory = files::GetDirectoryName(directory); + packages_path = directory + "/.packages"; + if (!PathExists(packages_path)) + packages_path = std::string(); } + return packages_path; +} - // Runtime controller is initialized here because it takes a reference to this - // object as its delegate. The delegate may be called in the constructor and - // we want to be fully initilazed by that point. - runtime_controller_ = std::make_unique( - *this, // runtime delegate - &vm, // VM - std::move(task_runners), // task runners - std::move(resource_context), // resource context - std::move(unref_queue) // skia unref queue - ); +std::string GetScriptUriFromPath(const std::string& path) { + return "file://" + SanitizePath(path); } -Engine::~Engine() { - if (legacy_sky_platform_) { - blink::ShutdownEngine(/* legacy_sky_platform_ */); - } +} // namespace + +Engine::Engine(PlatformView* platform_view) + : platform_view_(platform_view->GetWeakPtr()), + animator_(std::make_unique( + platform_view->rasterizer().GetWeakRasterizerPtr(), + platform_view->GetVsyncWaiter(), + this)), + load_script_error_(tonic::kNoError), + user_settings_data_("{}"), + activity_running_(false), + have_surface_(false), + weak_factory_(this) {} + +Engine::~Engine() {} + +void Engine::set_rasterizer(fml::WeakPtr rasterizer) { + animator_->set_rasterizer(rasterizer); } -fml::WeakPtr Engine::GetWeakPtr() const { - return weak_prototype_; +fml::WeakPtr Engine::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); } -bool Engine::UpdateAssetManager( - fxl::RefPtr new_asset_manager) { - if (asset_manager_ == new_asset_manager) { - return false; +#if !FLUTTER_AOT +#elif OS(IOS) +#elif OS(ANDROID) +// TODO(bkonyi): do we even get here for Windows? +static const uint8_t* MemMapSnapshot(const std::string& aot_snapshot_path, + const std::string& default_file_name, + const std::string& settings_file_name, + bool executable) { + std::string asset_path; + if (settings_file_name.empty()) { + asset_path = aot_snapshot_path + "/" + default_file_name; + } else { + asset_path = aot_snapshot_path + "/" + settings_file_name; } - asset_manager_ = new_asset_manager; +#if OS(WIN) + HANDLE file_handle_ = + CreateFileA(reinterpret_cast(path.c_str()), GENERIC_READ, + FILE_SHARE_READ, nullptr, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, nullptr); - if (!asset_manager_) { - return false; + if (file_handle_ == INVALID_HANDLE_VALUE) { + return; } - if (settings_.using_blink) { - // Using blink as the text engine. - blink::FontFallbackList::SetUseTestFonts(settings_.use_test_fonts); - } else { - // Using libTXT as the text engine. - if (settings_.use_test_fonts) { - blink::FontCollection::ForProcess().RegisterTestFonts(); - } else { - blink::FontCollection::ForProcess().RegisterFonts(*asset_manager_.get()); - } + size_ = GetFileSize(file_handle_, nullptr); + if (size_ == INVALID_FILE_SIZE) { + size_ = 0; + return; } - return true; -} + int mapping_flags = executable ? PAGE_EXECUTE_READ : PAGE_READONLY; + mapping_handle_ = CreateFileMapping(file_handle_, nullptr, mapping_flags, 0, + size_, nullptr); -bool Engine::Restart(RunConfiguration configuration) { - TRACE_EVENT0("flutter", "Engine::Restart"); - if (!configuration.IsValid()) { - FXL_LOG(ERROR) << "Engine run configuration was invalid."; - return false; - } - runtime_controller_ = runtime_controller_->Clone(); - UpdateAssetManager(nullptr); - return Run(std::move(configuration)); -} + CloseHandle(file_handle_); -bool Engine::Run(RunConfiguration configuration) { - if (!configuration.IsValid()) { - FXL_LOG(ERROR) << "Engine run configuration was invalid."; - return false; + if (mapping_handle_ == INVALID_HANDLE_VALUE) { + return; } - if (!PrepareAndLaunchIsolate(std::move(configuration))) { - return false; + int access_flags = FILE_MAP_READ; + if (executable) { + access_flags |= FILE_MAP_EXECUTE; } + auto mapping = MapViewOfFile(mapping_handle_, access_flags, 0, 0, size_); - auto isolate = runtime_controller_->GetRootIsolate(); + if (mapping == INVALID_HANDLE_VALUE) { + CloseHandle(mapping_handle_); + mapping_handle_ = INVALID_HANDLE_VALUE; + return; + } - bool isolate_running = - isolate && isolate->GetPhase() == blink::DartIsolate::Phase::Running; + void* symbol = static_cast(mapping); + if (symbol == NULL) { + return nullptr; + } +#else + struct stat info; + if (stat(asset_path.c_str(), &info) < 0) { + return nullptr; + } + int64_t asset_size = info.st_size; - if (isolate_running) { - tonic::DartState::Scope scope(isolate.get()); + fxl::UniqueFD fd(HANDLE_EINTR(open(asset_path.c_str(), O_RDONLY))); + if (fd.get() == -1) { + return nullptr; + } - if (settings_.root_isolate_create_callback) { - settings_.root_isolate_create_callback(); - } + int mmap_flags = PROT_READ; + if (executable) + mmap_flags |= PROT_EXEC; - if (settings_.root_isolate_shutdown_callback) { - isolate->AddIsolateShutdownCallback( - settings_.root_isolate_shutdown_callback); - } + void* symbol = mmap(NULL, asset_size, mmap_flags, MAP_PRIVATE, fd.get(), 0); + if (symbol == MAP_FAILED) { + return nullptr; + } +#endif + return reinterpret_cast(symbol); +} +#endif - // Blink uses a per isolate font selector. - if (settings_.using_blink) { - if (settings_.use_test_fonts) { - blink::TestFontSelector::Install(); - } else { - blink::AssetFontSelector::Install(asset_manager_); - } +static const uint8_t* default_isolate_snapshot_data = nullptr; +static const uint8_t* default_isolate_snapshot_instr = nullptr; + +void Engine::Init(const std::string& bundle_path) { + const uint8_t* vm_snapshot_data; + const uint8_t* vm_snapshot_instr; +#if !FLUTTER_AOT + vm_snapshot_data = ::kDartVmSnapshotData; + vm_snapshot_instr = ::kDartVmSnapshotInstructions; + default_isolate_snapshot_data = ::kDartIsolateCoreSnapshotData; + default_isolate_snapshot_instr = ::kDartIsolateCoreSnapshotInstructions; +#elif OS(IOS) + const char* kDartApplicationLibraryPath = "App.framework/App"; + const char* application_library_path = kDartApplicationLibraryPath; + const blink::Settings& settings = blink::Settings::Get(); + const std::string& application_library_path_setting = + settings.application_library_path; + if (!application_library_path_setting.empty()) { + application_library_path = application_library_path_setting.c_str(); + } + dlerror(); // clear previous errors on thread + void* library_handle = dlopen(application_library_path, RTLD_NOW); + const char* err = dlerror(); + if (err != nullptr) { + FXL_LOG(FATAL) << "dlopen failed: " << err; + } + vm_snapshot_data = reinterpret_cast( + dlsym(library_handle, "kDartVmSnapshotData")); + vm_snapshot_instr = reinterpret_cast( + dlsym(library_handle, "kDartVmSnapshotInstructions")); + default_isolate_snapshot_data = reinterpret_cast( + dlsym(library_handle, "kDartIsolateSnapshotData")); + default_isolate_snapshot_instr = reinterpret_cast( + dlsym(library_handle, "kDartIsolateSnapshotInstructions")); +#elif OS(ANDROID) || OS(WIN) + const blink::Settings& settings = blink::Settings::Get(); + const std::string& aot_shared_library_path = settings.aot_shared_library_path; + const std::string& aot_snapshot_path = settings.aot_snapshot_path; + + if (!aot_shared_library_path.empty()) { + FXL_CHECK(aot_snapshot_path.empty()); + dlerror(); // clear previous errors on thread + void* library_handle = dlopen(aot_shared_library_path.c_str(), RTLD_NOW); + const char* err = dlerror(); + if (err != nullptr) { + FXL_LOG(FATAL) << "dlopen failed: " << err; } + vm_snapshot_data = reinterpret_cast( + dlsym(library_handle, "_kDartVmSnapshotData")); + vm_snapshot_instr = reinterpret_cast( + dlsym(library_handle, "_kDartVmSnapshotInstructions")); + default_isolate_snapshot_data = reinterpret_cast( + dlsym(library_handle, "_kDartIsolateSnapshotData")); + default_isolate_snapshot_instr = reinterpret_cast( + dlsym(library_handle, "_kDartIsolateSnapshotInstructions")); + } else { + FXL_CHECK(!aot_snapshot_path.empty()); + vm_snapshot_data = + MemMapSnapshot(aot_snapshot_path, "vm_snapshot_data", + settings.aot_vm_snapshot_data_filename, false); + vm_snapshot_instr = + MemMapSnapshot(aot_snapshot_path, "vm_snapshot_instr", + settings.aot_vm_snapshot_instr_filename, true); + default_isolate_snapshot_data = + MemMapSnapshot(aot_snapshot_path, "isolate_snapshot_data", + settings.aot_isolate_snapshot_data_filename, false); + default_isolate_snapshot_instr = + MemMapSnapshot(aot_snapshot_path, "isolate_snapshot_instr", + settings.aot_isolate_snapshot_instr_filename, true); } - - return isolate_running; +#else +#error Unknown OS +#endif + blink::InitRuntime(vm_snapshot_data, vm_snapshot_instr, + default_isolate_snapshot_data, + default_isolate_snapshot_instr, bundle_path); } -bool Engine::PrepareAndLaunchIsolate(RunConfiguration configuration) { - TRACE_EVENT0("flutter", "Engine::PrepareAndLaunchIsolate"); +const std::string Engine::main_entrypoint_ = "main"; - UpdateAssetManager(configuration.GetAssetManager()); - - auto isolate_configuration = configuration.TakeIsolateConfiguration(); - - auto isolate = runtime_controller_->GetRootIsolate(); +void Engine::RunBundle(const std::string& bundle_path, + const std::string& entrypoint, + bool reuse_runtime_controller) { + TRACE_EVENT0("flutter", "Engine::RunBundle"); + ConfigureAssetBundle(bundle_path); + DoRunBundle(GetScriptUriFromPath(bundle_path), entrypoint, + reuse_runtime_controller); +} - if (!isolate_configuration->PrepareIsolate(isolate)) { - FXL_DLOG(ERROR) << "Could not prepare to run the isolate."; - return false; +void Engine::DoRunBundle(const std::string& script_uri, + const std::string& entrypoint, + bool reuse_runtime_controller) { + ConfigureRuntime(script_uri, reuse_runtime_controller); + if (blink::IsRunningPrecompiledCode()) { + runtime_->dart_controller()->RunFromPrecompiledSnapshot(entrypoint); + } else { + std::vector kernel; + if (GetAssetAsBuffer(blink::kKernelAssetKey, &kernel)) { + runtime_->dart_controller()->RunFromKernel(kernel, entrypoint); + return; + } + std::vector snapshot; + if (!GetAssetAsBuffer(blink::kSnapshotAssetKey, &snapshot)) + return; + runtime_->dart_controller()->RunFromScriptSnapshot( + snapshot.data(), snapshot.size(), entrypoint); } +} - if (!isolate->Run(configuration.GetEntrypoint())) { - FXL_DLOG(ERROR) << "Could not run the isolate."; - return false; +// TODO(jsimmons): merge this with RunBundle +void Engine::RunBundleWithAssets( + fxl::RefPtr asset_provider, + const std::string& bundle_path, + const std::string& entrypoint, + bool reuse_runtime_controller) { + TRACE_EVENT0("flutter", "Engine::RunBundleWithAssets"); + asset_provider_ = asset_provider; + DoRunBundle(GetScriptUriFromPath(bundle_path), entrypoint, + reuse_runtime_controller); +} + +void Engine::RunBundleAndSource(const std::string& bundle_path, + const std::string& main, + const std::string& packages, + bool reuse_runtime_controller) { + TRACE_EVENT0("flutter", "Engine::RunBundleAndSource"); + FXL_CHECK(!blink::IsRunningPrecompiledCode()) + << "Cannot run from source in a precompiled build."; + std::string packages_path = packages; + if (packages_path.empty()) + packages_path = FindPackagesPath(main); + + if (!bundle_path.empty()) + ConfigureAssetBundle(bundle_path); + + ConfigureRuntime(main, reuse_runtime_controller); + + if (blink::GetKernelPlatformBinary() != nullptr) { + std::vector kernel; + if (!files::ReadFileToVector(main, &kernel)) { + load_script_error_ = tonic::kUnknownErrorType; + } + load_script_error_ = runtime_->dart_controller()->RunFromKernel(kernel); + } else { + load_script_error_ = + runtime_->dart_controller()->RunFromSource(main, packages_path); } - - return true; } void Engine::BeginFrame(fxl::TimePoint frame_time) { TRACE_EVENT0("flutter", "Engine::BeginFrame"); - runtime_controller_->BeginFrame(frame_time); + if (runtime_) + runtime_->BeginFrame(frame_time); } void Engine::NotifyIdle(int64_t deadline) { TRACE_EVENT0("flutter", "Engine::NotifyIdle"); - runtime_controller_->NotifyIdle(deadline); + if (runtime_) + runtime_->NotifyIdle(deadline); +} + +void Engine::RunFromSource(const std::string& main, + const std::string& packages, + const std::string& bundle_path) { + RunBundleAndSource(bundle_path, main, packages); } -std::pair Engine::GetUIIsolateReturnCode() { - return runtime_controller_->GetRootIsolateReturnCode(); +void Engine::SetAssetBundlePath(const std::string& bundle_path) { + TRACE_EVENT0("flutter", "Engine::SetAssetBundlePath"); + ConfigureAssetBundle(bundle_path); } Dart_Port Engine::GetUIIsolateMainPort() { - return runtime_controller_->GetMainPort(); + if (!runtime_) + return ILLEGAL_PORT; + return runtime_->GetMainPort(); } std::string Engine::GetUIIsolateName() { - return runtime_controller_->GetIsolateName(); + if (!runtime_) { + return ""; + } + return runtime_->GetIsolateName(); } bool Engine::UIIsolateHasLivePorts() { - return runtime_controller_->HasLivePorts(); + if (!runtime_) + return false; + return runtime_->HasLivePorts(); } tonic::DartErrorHandleType Engine::GetUIIsolateLastError() { - return runtime_controller_->GetLastError(); + if (!runtime_) + return tonic::kNoError; + return runtime_->GetLastError(); } tonic::DartErrorHandleType Engine::GetLoadScriptError() { return load_script_error_; } -void Engine::OnOutputSurfaceCreated() { +void Engine::OnOutputSurfaceCreated(const fxl::Closure& gpu_continuation) { + blink::Threads::Gpu()->PostTask(gpu_continuation); have_surface_ = true; StartAnimatorIfPossible(); - ScheduleFrame(); + if (runtime_) + ScheduleFrame(); } -void Engine::OnOutputSurfaceDestroyed() { +void Engine::OnOutputSurfaceDestroyed(const fxl::Closure& gpu_continuation) { have_surface_ = false; StopAnimator(); + blink::Threads::Gpu()->PostTask(gpu_continuation); } void Engine::SetViewportMetrics(const blink::ViewportMetrics& metrics) { @@ -237,7 +436,8 @@ void Engine::SetViewportMetrics(const blink::ViewportMetrics& metrics) { viewport_metrics_.physical_height != metrics.physical_height || viewport_metrics_.physical_width != metrics.physical_width; viewport_metrics_ = metrics; - runtime_controller_->SetViewportMetrics(viewport_metrics_); + if (runtime_) + runtime_->SetViewportMetrics(viewport_metrics_); if (animator_) { if (dimensions_changed) animator_->SetDimensionChangePending(); @@ -259,7 +459,8 @@ void Engine::DispatchPlatformMessage( return; } - if (runtime_controller_->DispatchPlatformMessage(std::move(message))) { + if (runtime_) { + runtime_->DispatchPlatformMessage(std::move(message)); return; } @@ -292,6 +493,7 @@ bool Engine::HandleLifecyclePlatformMessage(blink::PlatformMessage* message) { bool Engine::HandleNavigationPlatformMessage( fxl::RefPtr message) { + FXL_DCHECK(!runtime_); const auto& data = message->data(); rapidjson::Document document; @@ -330,33 +532,99 @@ bool Engine::HandleLocalizationPlatformMessage( if (!language.IsString() || !country.IsString()) return false; - return runtime_controller_->SetLocale(language.GetString(), - country.GetString()); + language_code_ = language.GetString(); + country_code_ = country.GetString(); + if (runtime_) + runtime_->SetLocale(language_code_, country_code_); + return true; } void Engine::HandleSettingsPlatformMessage(blink::PlatformMessage* message) { const auto& data = message->data(); std::string jsonData(reinterpret_cast(data.data()), data.size()); - if (runtime_controller_->SetUserSettingsData(std::move(jsonData)) && - have_surface_) { - ScheduleFrame(); + user_settings_data_ = jsonData; + if (runtime_) { + runtime_->SetUserSettingsData(user_settings_data_); + if (have_surface_) + ScheduleFrame(); } } -void Engine::DispatchPointerDataPacket(const blink::PointerDataPacket& packet) { - runtime_controller_->DispatchPointerDataPacket(packet); +void Engine::DispatchPointerDataPacket(const PointerDataPacket& packet) { + if (runtime_) + runtime_->DispatchPointerDataPacket(packet); } void Engine::DispatchSemanticsAction(int id, blink::SemanticsAction action, std::vector args) { - runtime_controller_->DispatchSemanticsAction(id, action, std::move(args)); + if (runtime_) + runtime_->DispatchSemanticsAction(id, action, std::move(args)); } void Engine::SetSemanticsEnabled(bool enabled) { - runtime_controller_->SetSemanticsEnabled(enabled); + semantics_enabled_ = enabled; + if (runtime_) + runtime_->SetSemanticsEnabled(semantics_enabled_); +} + +void Engine::ConfigureAssetBundle(const std::string& path) { + asset_provider_ = fxl::MakeRefCounted(path); + + struct stat stat_result = {}; + + // TODO(abarth): We should reset directory_asset_bundle_, but that might break + // custom font loading in hot reload. + + if (::stat(path.c_str(), &stat_result) != 0) { + FXL_LOG(INFO) << "Could not configure asset bundle at path: " << path; + return; + } + + std::string flx_path; + if (S_ISDIR(stat_result.st_mode)) { + flx_path = files::GetDirectoryName(path) + "/app.flx"; + } else if (S_ISREG(stat_result.st_mode)) { + flx_path = path; + } + + if (PathExists(flx_path)) { + asset_store_ = fxl::MakeRefCounted( + blink::GetUnzipperProviderForPath(flx_path)); + } +} + +void Engine::ConfigureRuntime(const std::string& script_uri, + bool reuse_runtime_controller) { + if (runtime_ && reuse_runtime_controller) { + return; + } + runtime_ = blink::RuntimeController::Create(this); + runtime_->CreateDartController(std::move(script_uri), + default_isolate_snapshot_data, + default_isolate_snapshot_instr); + runtime_->SetViewportMetrics(viewport_metrics_); + runtime_->SetLocale(language_code_, country_code_); + runtime_->SetUserSettingsData(user_settings_data_); + runtime_->SetSemanticsEnabled(semantics_enabled_); +} + +void Engine::DidCreateMainIsolate(Dart_Isolate isolate) { + if (blink::Settings::Get().use_test_fonts) { + blink::TestFontSelector::Install(); + if (!blink::Settings::Get().using_blink) + blink::FontCollection::ForProcess().RegisterTestFonts(); + } else if (asset_provider_) { + blink::AssetFontSelector::Install(asset_provider_); + if (!blink::Settings::Get().using_blink) { + blink::FontCollection::ForProcess().RegisterFontsFromAssetProvider( + asset_provider_); + } + } } +void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {} + void Engine::StopAnimator() { animator_->Stop(); } @@ -391,34 +659,49 @@ void Engine::Render(std::unique_ptr layer_tree) { } void Engine::UpdateSemantics(blink::SemanticsNodeUpdates update) { - delegate_.OnEngineUpdateSemantics(*this, std::move(update)); + blink::Threads::Platform()->PostTask(fxl::MakeCopyable([ + platform_view = platform_view_.lock(), update = std::move(update) + ]() mutable { + if (platform_view) + platform_view->UpdateSemantics(std::move(update)); + })); } void Engine::HandlePlatformMessage( fxl::RefPtr message) { if (message->channel() == kAssetChannel) { HandleAssetPlatformMessage(std::move(message)); - } else { - delegate_.OnEngineHandlePlatformMessage(*this, std::move(message)); + return; } + blink::Threads::Platform()->PostTask([ + platform_view = platform_view_.lock(), message = std::move(message) + ]() mutable { + if (platform_view) + platform_view->HandlePlatformMessage(std::move(message)); + }); } void Engine::HandleAssetPlatformMessage( fxl::RefPtr message) { fxl::RefPtr response = message->response(); - if (!response) { + if (!response) return; - } const auto& data = message->data(); std::string asset_name(reinterpret_cast(data.data()), data.size()); - std::vector asset_data; - if (asset_manager_ && asset_manager_->GetAsBuffer(asset_name, &asset_data)) { + if (GetAssetAsBuffer(asset_name, &asset_data)) { response->Complete(std::move(asset_data)); } else { response->CompleteEmpty(); } } +bool Engine::GetAssetAsBuffer(const std::string& name, + std::vector* data) { + return ((asset_provider_ && + asset_provider_->GetAsBuffer(name, data)) || + (asset_store_ && asset_store_->GetAsBuffer(name, data))); +} + } // namespace shell diff --git a/shell/common/engine.h b/shell/common/engine.h index ede442ee3e8a4..a0c5183338a43 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -5,144 +5,131 @@ #ifndef SHELL_COMMON_ENGINE_H_ #define SHELL_COMMON_ENGINE_H_ -#include -#include - -#include "flutter/assets/asset_manager.h" -#include "flutter/common/task_runners.h" -#include "flutter/lib/ui/semantics/semantics_node.h" +#include "flutter/assets/zip_asset_store.h" +#include "flutter/assets/asset_provider.h" #include "flutter/lib/ui/window/platform_message.h" #include "flutter/lib/ui/window/viewport_metrics.h" -#include "flutter/runtime/dart_vm.h" -#include "flutter/runtime/platform_impl.h" #include "flutter/runtime/runtime_controller.h" #include "flutter/runtime/runtime_delegate.h" -#include "flutter/shell/common/animator.h" #include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/run_configuration.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/weak_ptr.h" #include "third_party/skia/include/core/SkPicture.h" +namespace blink { +class DirectoryAssetBundle; +class ZipAssetBundle; +} // namespace blink + namespace shell { +class PlatformView; +class Animator; +using PointerDataPacket = blink::PointerDataPacket; -class Engine final : public blink::RuntimeDelegate { +class Engine : public blink::RuntimeDelegate { public: - class Delegate { - public: - virtual void OnEngineUpdateSemantics( - const Engine& engine, - blink::SemanticsNodeUpdates update) = 0; - - virtual void OnEngineHandlePlatformMessage( - const Engine& engine, - fxl::RefPtr message) = 0; - }; - - Engine(Delegate& delegate, - const blink::DartVM& vm, - blink::TaskRunners task_runners, - blink::Settings settings, - std::unique_ptr animator, - fml::WeakPtr resource_context, - fxl::RefPtr unref_queue); + explicit Engine(PlatformView* platform_view); ~Engine() override; - fml::WeakPtr GetWeakPtr() const; + fml::WeakPtr GetWeakPtr(); - FXL_WARN_UNUSED_RESULT - bool Run(RunConfiguration configuration); + static void Init(const std::string& bundle_path); - // Used to "cold reload" a running application where the shell (along with the - // platform view and its rasterizer bindings) remains the same but the root - // isolate is torn down and restarted with the new configuration. Only used in - // the development workflow. - FXL_WARN_UNUSED_RESULT - bool Restart(RunConfiguration configuration); + void RunBundle(const std::string& bundle_path, + const std::string& entrypoint = main_entrypoint_, + bool reuse_runtime_controller = false); - bool UpdateAssetManager(fxl::RefPtr asset_manager); + // Uses the given provider to locate assets. + void RunBundleWithAssets(fxl::RefPtr asset_provider, + const std::string& bundle_path, + const std::string& entrypoint = main_entrypoint_, + bool reuse_runtime_controller = false); - void BeginFrame(fxl::TimePoint frame_time); + // Uses the given source code instead of looking inside the bundle for the + // source code. + void RunBundleAndSource(const std::string& bundle_path, + const std::string& main, + const std::string& packages, + bool reuse_runtime_controller = false); + void BeginFrame(fxl::TimePoint frame_time); void NotifyIdle(int64_t deadline); - Dart_Port GetUIIsolateMainPort(); + void RunFromSource(const std::string& main, + const std::string& packages, + const std::string& bundle); + void SetAssetBundlePath(const std::string& bundle_path); + Dart_Port GetUIIsolateMainPort(); std::string GetUIIsolateName(); - bool UIIsolateHasLivePorts(); - tonic::DartErrorHandleType GetUIIsolateLastError(); - tonic::DartErrorHandleType GetLoadScriptError(); - std::pair GetUIIsolateReturnCode(); - - void OnOutputSurfaceCreated(); - - void OnOutputSurfaceDestroyed(); - + void OnOutputSurfaceCreated(const fxl::Closure& gpu_continuation); + void OnOutputSurfaceDestroyed(const fxl::Closure& gpu_continuation); void SetViewportMetrics(const blink::ViewportMetrics& metrics); - void DispatchPlatformMessage(fxl::RefPtr message); - - void DispatchPointerDataPacket(const blink::PointerDataPacket& packet); - + void DispatchPointerDataPacket(const PointerDataPacket& packet); void DispatchSemanticsAction(int id, blink::SemanticsAction action, std::vector args); - void SetSemanticsEnabled(bool enabled); - void ScheduleFrame(bool regenerate_layer_tree = true) override; - private: - Engine::Delegate& delegate_; - const blink::Settings settings_; - std::unique_ptr animator_; - std::unique_ptr runtime_controller_; - std::unique_ptr legacy_sky_platform_; - tonic::DartErrorHandleType load_script_error_; - std::string initial_route_; - blink::ViewportMetrics viewport_metrics_; - fxl::RefPtr asset_manager_; - bool activity_running_; - bool have_surface_; - fml::WeakPtr weak_prototype_; - fml::WeakPtrFactory weak_factory_; + void set_rasterizer(fml::WeakPtr rasterizer); - // |blink::RuntimeDelegate| + private: + // RuntimeDelegate methods: std::string DefaultRouteName() override; - - // |blink::RuntimeDelegate| void Render(std::unique_ptr layer_tree) override; - - // |blink::RuntimeDelegate| void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - - // |blink::RuntimeDelegate| void HandlePlatformMessage( fxl::RefPtr message) override; + void DidCreateMainIsolate(Dart_Isolate isolate) override; + void DidCreateSecondaryIsolate(Dart_Isolate isolate) override; void StopAnimator(); - void StartAnimatorIfPossible(); - bool HandleLifecyclePlatformMessage(blink::PlatformMessage* message); + void DoRunBundle(const std::string& script_uri, + const std::string& entrypoint, + bool reuse_runtime_controller); + void ConfigureAssetBundle(const std::string& path); + void ConfigureRuntime(const std::string& script_uri, + bool reuse_runtime_controller = false); + + bool HandleLifecyclePlatformMessage(blink::PlatformMessage* message); bool HandleNavigationPlatformMessage( fxl::RefPtr message); - bool HandleLocalizationPlatformMessage(blink::PlatformMessage* message); - void HandleSettingsPlatformMessage(blink::PlatformMessage* message); void HandleAssetPlatformMessage(fxl::RefPtr message); - bool GetAssetAsBuffer(const std::string& name, std::vector* data); - bool PrepareAndLaunchIsolate(RunConfiguration configuration); + static const std::string main_entrypoint_; + + fxl::RefPtr asset_provider_; + std::weak_ptr platform_view_; + std::unique_ptr animator_; + std::unique_ptr runtime_; + tonic::DartErrorHandleType load_script_error_; + std::string initial_route_; + blink::ViewportMetrics viewport_metrics_; + std::string language_code_; + std::string country_code_; + std::string user_settings_data_; + bool semantics_enabled_ = false; + // TODO(zarah): Remove usage of asset_store_ once app.flx is removed. + fxl::RefPtr asset_store_; + fxl::RefPtr directory_asset_bundle_; + // TODO(eseidel): This should move into an AnimatorStateMachine. + bool activity_running_; + bool have_surface_; + fml::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(Engine); }; diff --git a/shell/common/io_manager.cc b/shell/common/io_manager.cc deleted file mode 100644 index 4161422978fcf..0000000000000 --- a/shell/common/io_manager.cc +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/shell/common/io_manager.h" - -#include "flutter/fml/message_loop.h" -#include "third_party/skia/include/gpu/gl/GrGLInterface.h" - -namespace shell { - -sk_sp IOManager::CreateCompatibleResourceLoadingContext( - GrBackend backend) { - if (backend != GrBackend::kOpenGL_GrBackend) { - return nullptr; - } - - GrContextOptions options = {}; - - // There is currently a bug with doing GPU YUV to RGB conversions on the IO - // thread. The necessary work isn't being flushed or synchronized with the - // other threads correctly, so the textures end up blank. For now, suppress - // that feature, which will cause texture uploads to do CPU YUV conversion. - options.fDisableGpuYUVConversion = true; - - if (auto context = GrContext::MakeGL(GrGLMakeNativeInterface(), options)) { - // Do not cache textures created by the image decoder. These textures - // should be deleted when they are no longer referenced by an SkImage. - context->setResourceCacheLimits(0, 0); - return context; - } - - return nullptr; -} - -IOManager::IOManager(sk_sp resource_context, - fxl::RefPtr unref_queue_task_runner) - : resource_context_(std::move(resource_context)), - resource_context_weak_factory_( - resource_context_ ? std::make_unique>( - resource_context_.get()) - : nullptr), - unref_queue_(fxl::MakeRefCounted( - std::move(unref_queue_task_runner), - fxl::TimeDelta::FromMilliseconds(250))), - weak_factory_(this) { - if (!resource_context_) { - FXL_DLOG(WARNING) << "The IO manager was initialized without a resource " - "context. Async texture uploads will be disabled. " - "Expect performance degradation."; - } - - if (resource_context_weak_factory_) { - resource_context_weak_prototype_ = - resource_context_weak_factory_->GetWeakPtr(); - } -} - -IOManager::~IOManager() { - // Last chance to drain the IO queue as the platform side reference to the - // underlying OpenGL context may be going away. - unref_queue_->Drain(); -} - -fml::WeakPtr IOManager::GetResourceContext() const { - return resource_context_weak_prototype_; -} - -fxl::RefPtr IOManager::GetSkiaUnrefQueue() const { - return unref_queue_; -} - -} // namespace shell diff --git a/shell/common/io_manager.h b/shell/common/io_manager.h deleted file mode 100644 index 1077a28d0ae36..0000000000000 --- a/shell/common/io_manager.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017 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_COMMON_IO_MANAGER_H_ -#define FLUTTER_SHELL_COMMON_IO_MANAGER_H_ - -#include - -#include "flutter/flow/skia_gpu_object.h" -#include "flutter/fml/memory/weak_ptr.h" -#include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" -#include "third_party/skia/include/gpu/GrContext.h" - -namespace shell { - -class IOManager { - public: - // Convenience methods for platforms to create a GrContext used to supply to - // the IOManager. The platforms may create the context themselves if they so - // desire. - static sk_sp CreateCompatibleResourceLoadingContext( - GrBackend backend); - - IOManager(sk_sp resource_context, - fxl::RefPtr unref_queue_task_runner); - - ~IOManager(); - - fml::WeakPtr GetResourceContext() const; - - fxl::RefPtr GetSkiaUnrefQueue() const; - - private: - // Resource context management. - sk_sp resource_context_; - fml::WeakPtr resource_context_weak_prototype_; - std::unique_ptr> - resource_context_weak_factory_; - - // Unref queue management. - fxl::RefPtr unref_queue_; - - fml::WeakPtrFactory weak_factory_; - - FXL_DISALLOW_COPY_AND_ASSIGN(IOManager); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_COMMON_IO_MANAGER_H_ diff --git a/shell/common/isolate_configuration.cc b/shell/common/isolate_configuration.cc deleted file mode 100644 index 0706ee5ab58df..0000000000000 --- a/shell/common/isolate_configuration.cc +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/shell/common/isolate_configuration.h" - -#include "flutter/runtime/dart_vm.h" - -namespace shell { - -IsolateConfiguration::IsolateConfiguration() = default; - -IsolateConfiguration::~IsolateConfiguration() = default; - -bool IsolateConfiguration::PrepareIsolate( - fml::WeakPtr isolate) { - if (!isolate) { - return false; - } - - if (isolate->GetPhase() != blink::DartIsolate::Phase::LibrariesSetup) { - FXL_DLOG(ERROR) - << "Isolate was in incorrect phase to be prepared for running."; - return false; - } - - return DoPrepareIsolate(*isolate); -} - -class PrecompiledIsolateConfiguration final : public IsolateConfiguration { - public: - PrecompiledIsolateConfiguration() = default; - - // |shell::IsolateConfiguration| - bool DoPrepareIsolate(blink::DartIsolate& isolate) override { - if (!blink::DartVM::IsRunningPrecompiledCode()) { - return false; - } - return isolate.PrepareForRunningFromPrecompiledCode(); - } - - private: - FXL_DISALLOW_COPY_AND_ASSIGN(PrecompiledIsolateConfiguration); -}; - -class SnapshotIsolateConfiguration : public IsolateConfiguration { - public: - SnapshotIsolateConfiguration(std::unique_ptr snapshot) - : snapshot_(std::move(snapshot)) {} - - // |shell::IsolateConfiguration| - bool DoPrepareIsolate(blink::DartIsolate& isolate) override { - if (blink::DartVM::IsRunningPrecompiledCode()) { - return false; - } - return isolate.PrepareForRunningFromSnapshot(std::move(snapshot_)); - } - - private: - std::unique_ptr snapshot_; - - FXL_DISALLOW_COPY_AND_ASSIGN(SnapshotIsolateConfiguration); -}; - -class SourceIsolateConfiguration final : public IsolateConfiguration { - public: - SourceIsolateConfiguration(std::string main_path, std::string packages_path) - : main_path_(std::move(main_path)), - packages_path_(std::move(packages_path)) {} - - // |shell::IsolateConfiguration| - bool DoPrepareIsolate(blink::DartIsolate& isolate) override { - if (blink::DartVM::IsRunningPrecompiledCode()) { - return false; - } - return isolate.PrepareForRunningFromSource(std::move(main_path_), - std::move(packages_path_)); - } - - private: - std::string main_path_; - std::string packages_path_; - - FXL_DISALLOW_COPY_AND_ASSIGN(SourceIsolateConfiguration); -}; - -std::unique_ptr IsolateConfiguration::InferFromSettings( - const blink::Settings& settings, - fxl::RefPtr asset_manager) { - // Running in AOT mode. - if (blink::DartVM::IsRunningPrecompiledCode()) { - return CreateForPrecompiledCode(); - } - - // Run from sources. - { - const auto& main = settings.main_dart_file_path; - const auto& packages = settings.packages_file_path; - if (main.size() != 0 && packages.size() != 0) { - return CreateForSource(std::move(main), std::move(packages)); - } - } - - // Running from kernel snapshot. - { - std::vector kernel; - if (asset_manager && asset_manager->GetAsBuffer( - settings.application_kernel_asset, &kernel)) { - return CreateForSnapshot( - std::make_unique(std::move(kernel))); - } - } - - // Running from script snapshot. - { - std::vector script_snapshot; - if (asset_manager && asset_manager->GetAsBuffer( - settings.script_snapshot_path, &script_snapshot)) { - return CreateForSnapshot( - std::make_unique(std::move(script_snapshot))); - } - } - - return nullptr; -} - -std::unique_ptr -IsolateConfiguration::CreateForPrecompiledCode() { - return std::make_unique(); -} - -std::unique_ptr IsolateConfiguration::CreateForSnapshot( - std::unique_ptr snapshot) { - return std::make_unique(std::move(snapshot)); -} - -std::unique_ptr IsolateConfiguration::CreateForSource( - std::string main_path, - std::string packages_path) { - return std::make_unique(std::move(main_path), - std::move(packages_path)); -} - -} // namespace shell diff --git a/shell/common/isolate_configuration.h b/shell/common/isolate_configuration.h deleted file mode 100644 index 82d06dac621b2..0000000000000 --- a/shell/common/isolate_configuration.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 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_COMMON_ISOLATE_CONFIGURATION_H_ -#define FLUTTER_SHELL_COMMON_ISOLATE_CONFIGURATION_H_ - -#include -#include - -#include "flutter/assets/asset_manager.h" -#include "flutter/assets/asset_resolver.h" -#include "flutter/common/settings.h" -#include "flutter/fml/mapping.h" -#include "flutter/fml/memory/weak_ptr.h" -#include "flutter/runtime/dart_isolate.h" -#include "lib/fxl/macros.h" - -namespace shell { - -class IsolateConfiguration { - public: - static std::unique_ptr InferFromSettings( - const blink::Settings& settings, - fxl::RefPtr asset_manager); - - static std::unique_ptr CreateForPrecompiledCode(); - - static std::unique_ptr CreateForSnapshot( - std::unique_ptr snapshot); - - static std::unique_ptr CreateForSource( - std::string main_path, - std::string packages_path); - - IsolateConfiguration(); - - virtual ~IsolateConfiguration(); - - bool PrepareIsolate(fml::WeakPtr isolate); - - protected: - virtual bool DoPrepareIsolate(blink::DartIsolate& isolate) = 0; - - private: - FXL_DISALLOW_COPY_AND_ASSIGN(IsolateConfiguration); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_COMMON_ISOLATE_CONFIGURATION_H_ diff --git a/shell/common/null_platform_view.cc b/shell/common/null_platform_view.cc new file mode 100644 index 0000000000000..49fdf5a935b80 --- /dev/null +++ b/shell/common/null_platform_view.cc @@ -0,0 +1,37 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/common/null_platform_view.h" + +#include "flutter/shell/common/null_rasterizer.h" +#include "flutter/shell/common/shell.h" + +namespace shell { + +NullPlatformView::NullPlatformView() + : PlatformView(std::make_unique()), weak_factory_(this) {} + +void NullPlatformView::Attach() { + CreateEngine(); +} + +NullPlatformView::~NullPlatformView() = default; + +fxl::WeakPtr NullPlatformView::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); +} + +bool NullPlatformView::ResourceContextMakeCurrent() { + return false; +} + +// Hot-reload of the null platform view is not supported. +void NullPlatformView::RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) {} + +void NullPlatformView::SetAssetBundlePath(const std::string& assets_directory) { +} + +} // namespace shell diff --git a/shell/common/null_platform_view.h b/shell/common/null_platform_view.h new file mode 100644 index 0000000000000..eb23d67b48a7c --- /dev/null +++ b/shell/common/null_platform_view.h @@ -0,0 +1,39 @@ +// Copyright 2017 The Chromium 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 COMMON_NULL_PLATFORM_VIEW_H_ +#define COMMON_NULL_PLATFORM_VIEW_H_ + +#include "flutter/shell/common/platform_view.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" + +namespace shell { + +class NullPlatformView : public PlatformView { + public: + NullPlatformView(); + + ~NullPlatformView(); + + fxl::WeakPtr GetWeakPtr(); + + virtual void Attach() override; + + bool ResourceContextMakeCurrent() override; + + void RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) override; + void SetAssetBundlePath(const std::string& assets_directory) override; + + private: + fxl::WeakPtrFactory weak_factory_; + + FXL_DISALLOW_COPY_AND_ASSIGN(NullPlatformView); +}; + +} // namespace shell + +#endif // COMMON_NULL_PLATFORM_VIEW_H_ diff --git a/shell/common/null_rasterizer.cc b/shell/common/null_rasterizer.cc new file mode 100644 index 0000000000000..81efdd11d4970 --- /dev/null +++ b/shell/common/null_rasterizer.cc @@ -0,0 +1,67 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/common/null_rasterizer.h" + +namespace shell { + +NullRasterizer::NullRasterizer() : weak_factory_(this) {} + +void NullRasterizer::Setup( + std::unique_ptr surface_or_null, + fxl::Closure rasterizer_continuation, + fxl::AutoResetWaitableEvent* setup_completion_event) { + surface_ = std::move(surface_or_null); + rasterizer_continuation(); + setup_completion_event->Signal(); +} + +void NullRasterizer::Teardown( + fxl::AutoResetWaitableEvent* teardown_completion_event) { + if (surface_) { + surface_.reset(); + } + teardown_completion_event->Signal(); +} + +fml::WeakPtr NullRasterizer::GetWeakRasterizerPtr() { + return weak_factory_.GetWeakPtr(); +} + +flow::LayerTree* NullRasterizer::GetLastLayerTree() { + return nullptr; +} + +void NullRasterizer::DrawLastLayerTree() { + // Null rasterizer. Nothing to do. +} + +flow::TextureRegistry& NullRasterizer::GetTextureRegistry() { + return *texture_registry_; +} + +void NullRasterizer::Clear(SkColor color, const SkISize& size) { + // Null rasterizer. Nothing to do. +} + +void NullRasterizer::Draw( + fxl::RefPtr> pipeline) { + FXL_ALLOW_UNUSED_LOCAL( + pipeline->Consume([](std::unique_ptr) { + // Drop the layer tree on the floor. We only need the pipeline empty so + // that frame requests are not deferred indefinitely due to + // backpressure. + })); +} + +void NullRasterizer::AddNextFrameCallback(fxl::Closure nextFrameCallback) { + // Null rasterizer. Nothing to do. +} + +void NullRasterizer::SetTextureRegistry( + flow::TextureRegistry* textureRegistry) { + texture_registry_ = textureRegistry; +} + +} // namespace shell diff --git a/shell/common/null_rasterizer.h b/shell/common/null_rasterizer.h new file mode 100644 index 0000000000000..8558a3c3accaa --- /dev/null +++ b/shell/common/null_rasterizer.h @@ -0,0 +1,51 @@ +// Copyright 2016 The Chromium 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_COMMON_NULL_RASTERIZER_H_ +#define FLUTTER_SHELL_COMMON_NULL_RASTERIZER_H_ + +#include "flutter/shell/common/rasterizer.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" + +namespace shell { + +class NullRasterizer : public Rasterizer { + public: + NullRasterizer(); + + void Setup(std::unique_ptr surface_or_null, + fxl::Closure rasterizer_continuation, + fxl::AutoResetWaitableEvent* setup_completion_event) override; + + void Teardown( + fxl::AutoResetWaitableEvent* teardown_completion_event) override; + + void Clear(SkColor color, const SkISize& size) override; + + fml::WeakPtr GetWeakRasterizerPtr() override; + + flow::LayerTree* GetLastLayerTree() override; + + void DrawLastLayerTree() override; + + flow::TextureRegistry& GetTextureRegistry() override; + + void Draw(fxl::RefPtr> pipeline) override; + + void AddNextFrameCallback(fxl::Closure nextFrameCallback) override; + + void SetTextureRegistry(flow::TextureRegistry* textureRegistry) override; + + private: + std::unique_ptr surface_; + fml::WeakPtrFactory weak_factory_; + flow::TextureRegistry* texture_registry_; + + FXL_DISALLOW_COPY_AND_ASSIGN(NullRasterizer); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_COMMON_NULL_RASTERIZER_H_ diff --git a/shell/common/platform_view.cc b/shell/common/platform_view.cc index b2bfce051a5bf..2d5715a1733bd 100644 --- a/shell/common/platform_view.cc +++ b/shell/common/platform_view.cc @@ -6,74 +6,124 @@ #include +#include "flutter/common/threads.h" +#include "flutter/lib/ui/painting/resource_context.h" #include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/shell.h" #include "flutter/shell/common/vsync_waiter_fallback.h" #include "lib/fxl/functional/make_copyable.h" -#include "lib/fxl/synchronization/waitable_event.h" #include "third_party/skia/include/gpu/GrContextOptions.h" #include "third_party/skia/include/gpu/gl/GrGLInterface.h" namespace shell { -PlatformView::PlatformView(Delegate& delegate, blink::TaskRunners task_runners) - : delegate_(delegate), - task_runners_(std::move(task_runners)), - size_(SkISize::Make(0, 0)), - weak_factory_(this) { - weak_prototype_ = weak_factory_.GetWeakPtr(); +PlatformView::PlatformView(std::unique_ptr rasterizer) + : rasterizer_(std::move(rasterizer)), size_(SkISize::Make(0, 0)) { + rasterizer_->SetTextureRegistry(&texture_registry_); + Shell::Shared().AddPlatformView(this); } -PlatformView::~PlatformView() = default; +PlatformView::~PlatformView() { + Shell::Shared().RemovePlatformView(this); -std::unique_ptr PlatformView::CreateVSyncWaiter() { - FXL_DLOG(WARNING) - << "This platform does not provide a Vsync waiter implementation. A " - "simple timer based fallback is being used."; - return std::make_unique(task_runners_); + Rasterizer* rasterizer = rasterizer_.release(); + blink::Threads::Gpu()->PostTask([rasterizer]() { delete rasterizer; }); + + Engine* engine = engine_.release(); + blink::Threads::UI()->PostTask([engine]() { delete engine; }); } -void PlatformView::DispatchPlatformMessage( - fxl::RefPtr message) { - delegate_.OnPlatformViewDispatchPlatformMessage(*this, std::move(message)); +void PlatformView::SetRasterizer(std::unique_ptr rasterizer) { + Rasterizer* r = rasterizer_.release(); + blink::Threads::Gpu()->PostTask([r]() { delete r; }); + rasterizer_ = std::move(rasterizer); + rasterizer_->SetTextureRegistry(&texture_registry_); + engine_->set_rasterizer(rasterizer_->GetWeakRasterizerPtr()); } -void PlatformView::DispatchPointerDataPacket( - std::unique_ptr packet) { - delegate_.OnPlatformViewDispatchPointerDataPacket(*this, std::move(packet)); +void PlatformView::CreateEngine() { + engine_.reset(new Engine(this)); +} + +void PlatformView::DispatchPlatformMessage( + fxl::RefPtr message) { + blink::Threads::UI()->PostTask( + [engine = engine_->GetWeakPtr(), message = std::move(message)] { + if (engine) { + engine->DispatchPlatformMessage(message); + } + }); } void PlatformView::DispatchSemanticsAction(int32_t id, blink::SemanticsAction action, std::vector args) { - delegate_.OnPlatformViewDispatchSemanticsAction(*this, id, action, - std::move(args)); + blink::Threads::UI()->PostTask( + [engine = engine_->GetWeakPtr(), id, action, args = std::move(args)] { + if (engine) { + engine->DispatchSemanticsAction( + id, static_cast(action), std::move(args)); + } + }); } void PlatformView::SetSemanticsEnabled(bool enabled) { - delegate_.OnPlatformViewSetSemanticsEnabled(*this, enabled); + blink::Threads::UI()->PostTask([engine = engine_->GetWeakPtr(), enabled] { + if (engine) + engine->SetSemanticsEnabled(enabled); + }); } -void PlatformView::SetViewportMetrics(const blink::ViewportMetrics& metrics) { - delegate_.OnPlatformViewSetViewportMetrics(*this, metrics); +void PlatformView::NotifyCreated(std::unique_ptr surface) { + NotifyCreated(std::move(surface), []() {}); } -void PlatformView::NotifyCreated() { - delegate_.OnPlatformViewCreated(*this, CreateRenderingSurface()); +void PlatformView::NotifyCreated(std::unique_ptr surface, + fxl::Closure caller_continuation) { + fxl::AutoResetWaitableEvent latch; + + auto ui_continuation = fxl::MakeCopyable([this, // + surface = std::move(surface), // + caller_continuation, // + &latch]() mutable { + auto gpu_continuation = fxl::MakeCopyable([this, // + surface = std::move(surface), // + caller_continuation, // + &latch]() mutable { + // Runs on the GPU Thread. So does the Caller Continuation. + rasterizer_->Setup(std::move(surface), caller_continuation, &latch); + }); + // Runs on the UI Thread. + engine_->OnOutputSurfaceCreated(std::move(gpu_continuation)); + }); + + // Runs on the Platform Thread. + blink::Threads::UI()->PostTask(std::move(ui_continuation)); + + latch.Wait(); } void PlatformView::NotifyDestroyed() { - delegate_.OnPlatformViewDestroyed(*this); + fxl::AutoResetWaitableEvent latch; + + auto engine_continuation = [this, &latch]() { + rasterizer_->Teardown(&latch); + }; + + blink::Threads::UI()->PostTask([this, engine_continuation]() { + engine_->OnOutputSurfaceDestroyed(engine_continuation); + }); + + latch.Wait(); } -sk_sp PlatformView::CreateResourceContext() const { - FXL_DLOG(WARNING) << "This platform does not setup the resource " - "context on the IO thread for async texture uploads."; - return nullptr; +std::weak_ptr PlatformView::GetWeakPtr() { + return shared_from_this(); } -fml::WeakPtr PlatformView::GetWeakPtr() const { - return weak_prototype_; +VsyncWaiter* PlatformView::GetVsyncWaiter() { + if (!vsync_waiter_) + vsync_waiter_ = std::make_unique(); + return vsync_waiter_.get(); } void PlatformView::UpdateSemantics(blink::SemanticsNodeUpdates update) {} @@ -85,31 +135,71 @@ void PlatformView::HandlePlatformMessage( } void PlatformView::RegisterTexture(std::shared_ptr texture) { - delegate_.OnPlatformViewRegisterTexture(*this, std::move(texture)); + ASSERT_IS_PLATFORM_THREAD + blink::Threads::Gpu()->PostTask([this, texture]() { + rasterizer_->GetTextureRegistry().RegisterTexture(texture); + }); } void PlatformView::UnregisterTexture(int64_t texture_id) { - delegate_.OnPlatformViewUnregisterTexture(*this, texture_id); + ASSERT_IS_PLATFORM_THREAD + blink::Threads::Gpu()->PostTask([this, texture_id]() { + rasterizer_->GetTextureRegistry().UnregisterTexture(texture_id); + }); } void PlatformView::MarkTextureFrameAvailable(int64_t texture_id) { - delegate_.OnPlatformViewMarkTextureFrameAvailable(*this, texture_id); + ASSERT_IS_PLATFORM_THREAD + blink::Threads::UI()->PostTask([this]() { engine_->ScheduleFrame(false); }); } -std::unique_ptr PlatformView::CreateRenderingSurface() { - // We have a default implementation because tests create a platform view but - // never a rendering surface. - FXL_DCHECK(false) << "This platform does not provide a rendering surface but " - "it was notified of surface rendering surface creation."; - return nullptr; +void PlatformView::SetupResourceContextOnIOThread() { + fxl::AutoResetWaitableEvent latch; + + blink::Threads::IO()->PostTask( + [this, &latch]() { SetupResourceContextOnIOThreadPerform(&latch); }); + + latch.Wait(); } -void PlatformView::SetNextFrameCallback(fxl::Closure closure) { - if (!closure) { +void PlatformView::SetupResourceContextOnIOThreadPerform( + fxl::AutoResetWaitableEvent* latch) { + std::unique_ptr resourceContext = + blink::ResourceContext::Acquire(); + if (resourceContext->Get() != nullptr) { + // The resource context was already setup. This could happen if platforms + // try to setup a context multiple times, or, if there are multiple platform + // views. In any case, there is nothing else to do. So just signal the + // latch. + latch->Signal(); return; } - delegate_.OnPlatformViewSetNextFrameCallback(*this, std::move(closure)); + bool current = ResourceContextMakeCurrent(); + + if (!current) { + FXL_DLOG(WARNING) + << "WARNING: Could not setup a context on the resource loader."; + latch->Signal(); + return; + } + + GrContextOptions options; + // There is currently a bug with doing GPU YUV to RGB conversions on the IO + // thread. The necessary work isn't being flushed or synchronized with the + // other threads correctly, so the textures end up blank. For now, suppress + // that feature, which will cause texture uploads to do CPU YUV conversion. + options.fDisableGpuYUVConversion = true; + + blink::ResourceContext::Set( + GrContext::MakeGL(GrGLMakeNativeInterface(), options)); + + // Do not cache textures created by the image decoder. These textures should + // be deleted when they are no longer referenced by an SkImage. + if (resourceContext->Get()) + resourceContext->Get()->setResourceCacheLimits(0, 0); + + latch->Signal(); } } // namespace shell diff --git a/shell/common/platform_view.h b/shell/common/platform_view.h index 56179a6114777..66b1fcae10c79 100644 --- a/shell/common/platform_view.h +++ b/shell/common/platform_view.h @@ -7,104 +7,63 @@ #include -#include "flutter/common/task_runners.h" #include "flutter/flow/texture.h" -#include "flutter/fml/memory/weak_ptr.h" #include "flutter/lib/ui/semantics/semantics_node.h" -#include "flutter/lib/ui/window/platform_message.h" -#include "flutter/lib/ui/window/pointer_data_packet.h" -#include "flutter/lib/ui/window/viewport_metrics.h" +#include "flutter/shell/common/engine.h" +#include "flutter/shell/common/shell.h" #include "flutter/shell/common/surface.h" #include "flutter/shell/common/vsync_waiter.h" #include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" +#include "lib/fxl/synchronization/waitable_event.h" #include "third_party/skia/include/core/SkSize.h" #include "third_party/skia/include/gpu/GrContext.h" namespace shell { -class Shell; +class Rasterizer; -class PlatformView { +class PlatformView : public std::enable_shared_from_this { public: - class Delegate { - public: - virtual void OnPlatformViewCreated(const PlatformView& view, - std::unique_ptr surface) = 0; - - virtual void OnPlatformViewDestroyed(const PlatformView& view) = 0; - - virtual void OnPlatformViewSetNextFrameCallback(const PlatformView& view, - fxl::Closure closure) = 0; - - virtual void OnPlatformViewSetViewportMetrics( - const PlatformView& view, - const blink::ViewportMetrics& metrics) = 0; - - virtual void OnPlatformViewDispatchPlatformMessage( - const PlatformView& view, - fxl::RefPtr message) = 0; - - virtual void OnPlatformViewDispatchPointerDataPacket( - const PlatformView& view, - std::unique_ptr packet) = 0; - - virtual void OnPlatformViewDispatchSemanticsAction( - const PlatformView& view, - int32_t id, - blink::SemanticsAction action, - std::vector args) = 0; - - virtual void OnPlatformViewSetSemanticsEnabled(const PlatformView& view, - bool enabled) = 0; - - virtual void OnPlatformViewRegisterTexture( - const PlatformView& view, - std::shared_ptr texture) = 0; - - virtual void OnPlatformViewUnregisterTexture(const PlatformView& view, - int64_t texture_id) = 0; - - virtual void OnPlatformViewMarkTextureFrameAvailable( - const PlatformView& view, - int64_t texture_id) = 0; + struct SurfaceConfig { + uint8_t red_bits = 8; + uint8_t green_bits = 8; + uint8_t blue_bits = 8; + uint8_t alpha_bits = 8; + uint8_t depth_bits = 0; + uint8_t stencil_bits = 0; }; - explicit PlatformView(Delegate& delegate, blink::TaskRunners task_runners); + void SetupResourceContextOnIOThread(); virtual ~PlatformView(); - virtual std::unique_ptr CreateVSyncWaiter(); + virtual void Attach() = 0; void DispatchPlatformMessage(fxl::RefPtr message); - void DispatchSemanticsAction(int32_t id, blink::SemanticsAction action, std::vector args); + void SetSemanticsEnabled(bool enabled); - virtual void SetSemanticsEnabled(bool enabled); + void NotifyCreated(std::unique_ptr surface); - void SetViewportMetrics(const blink::ViewportMetrics& metrics); + void NotifyCreated(std::unique_ptr surface, + fxl::Closure continuation); - void NotifyCreated(); + void NotifyDestroyed(); - virtual void NotifyDestroyed(); + std::weak_ptr GetWeakPtr(); - // Unlike all other methods on the platform view, this one may be called on a - // non-platform task runner. - virtual sk_sp CreateResourceContext() const; + // The VsyncWaiter will live at least as long as the PlatformView. + virtual VsyncWaiter* GetVsyncWaiter(); - fml::WeakPtr GetWeakPtr() const; + virtual bool ResourceContextMakeCurrent() = 0; virtual void UpdateSemantics(blink::SemanticsNodeUpdates update); - virtual void HandlePlatformMessage( fxl::RefPtr message); - void SetNextFrameCallback(fxl::Closure closure); - - void DispatchPointerDataPacket( - std::unique_ptr packet); - // Called once per texture, on the platform thread. void RegisterTexture(std::shared_ptr texture); @@ -112,18 +71,34 @@ class PlatformView { void UnregisterTexture(int64_t texture_id); // Called once per texture update (e.g. video frame), on the platform thread. - void MarkTextureFrameAvailable(int64_t texture_id); + virtual void MarkTextureFrameAvailable(int64_t texture_id); + + void SetRasterizer(std::unique_ptr rasterizer); + + Rasterizer& rasterizer() { return *rasterizer_; } + Engine& engine() { return *engine_; } + + virtual void RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) = 0; + + virtual void SetAssetBundlePath(const std::string& assets_directory) = 0; protected: - PlatformView::Delegate& delegate_; - const blink::TaskRunners task_runners_; + explicit PlatformView(std::unique_ptr rasterizer); + + void CreateEngine(); + + void SetupResourceContextOnIOThreadPerform( + fxl::AutoResetWaitableEvent* event); + + SurfaceConfig surface_config_; + std::unique_ptr rasterizer_; + flow::TextureRegistry texture_registry_; + std::unique_ptr engine_; std::unique_ptr vsync_waiter_; SkISize size_; - fml::WeakPtr weak_prototype_; - fml::WeakPtrFactory weak_factory_; - - virtual std::unique_ptr CreateRenderingSurface(); private: FXL_DISALLOW_COPY_AND_ASSIGN(PlatformView); diff --git a/shell/common/platform_view_service_protocol.cc b/shell/common/platform_view_service_protocol.cc new file mode 100644 index 0000000000000..8785c4812e202 --- /dev/null +++ b/shell/common/platform_view_service_protocol.cc @@ -0,0 +1,447 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/common/platform_view_service_protocol.h" + +#include + +#include +#include + +#include "flutter/common/threads.h" +#include "flutter/shell/common/picture_serializer.h" +#include "flutter/shell/common/rasterizer.h" +#include "flutter/shell/common/shell.h" +#include "lib/fxl/memory/weak_ptr.h" +#include "third_party/skia/include/core/SkSurface.h" +#include "third_party/skia/src/utils/SkBase64.h" + +namespace shell { +namespace { + +constexpr char kViewIdPrefx[] = "_flutterView/"; +constexpr size_t kViewIdPrefxLength = sizeof(kViewIdPrefx) - 1; + +static intptr_t KeyIndex(const char** param_keys, + intptr_t num_params, + const char* key) { + if (param_keys == NULL) { + return -1; + } + for (intptr_t i = 0; i < num_params; i++) { + if (strcmp(param_keys[i], key) == 0) { + return i; + } + } + return -1; +} + +static const char* ValueForKey(const char** param_keys, + const char** param_values, + intptr_t num_params, + const char* key) { + intptr_t index = KeyIndex(param_keys, num_params, key); + if (index < 0) { + return NULL; + } + return param_values[index]; +} + +static bool ErrorMissingParameter(const char** json_object, const char* name) { + const intptr_t kInvalidParams = -32602; + std::stringstream response; + response << "{\"code\":" << std::to_string(kInvalidParams) << ","; + response << "\"message\":\"Invalid params\","; + response << "\"data\": {\"details\": \"" << name << "\"}}"; + *json_object = strdup(response.str().c_str()); + return false; +} + +static bool ErrorBadParameter(const char** json_object, + const char* name, + const char* value) { + const intptr_t kInvalidParams = -32602; + std::stringstream response; + response << "{\"code\":" << std::to_string(kInvalidParams) << ","; + response << "\"message\":\"Invalid params\","; + response << "\"data\": {\"details\": \"parameter: " << name << " has a bad "; + response << "value: " << value << "\"}}"; + *json_object = strdup(response.str().c_str()); + return false; +} + +static bool ErrorUnknownView(const char** json_object, const char* view_id) { + const intptr_t kInvalidParams = -32602; + std::stringstream response; + response << "{\"code\":" << std::to_string(kInvalidParams) << ","; + response << "\"message\":\"Invalid params\","; + response << "\"data\": {\"details\": \"view not found: " << view_id << "\"}}"; + *json_object = strdup(response.str().c_str()); + return false; +} + +static bool ErrorServer(const char** json_object, const char* message) { + const intptr_t kServerError = -32000; + std::stringstream response; + response << "{\"code\":" << std::to_string(kServerError) << ","; + response << "\"message\":\"" << message << "\"}"; + *json_object = strdup(response.str().c_str()); + return false; +} + +static void AppendIsolateRef(std::stringstream* stream, + int64_t main_port, + const std::string name) { + *stream << "{\"type\":\"@Isolate\",\"fixedId\":true,\"id\":\"isolates/"; + *stream << main_port << "\",\"name\":\"" << name << "\","; + *stream << "\"number\":\"" << main_port << "\"}"; +} + +static void AppendFlutterView(std::stringstream* stream, + uintptr_t view_id, + int64_t isolate_id, + const std::string isolate_name) { + *stream << "{\"type\":\"FlutterView\", \"id\": \"" << kViewIdPrefx << "0x" + << std::hex << view_id << std::dec << "\""; + if (isolate_id != ILLEGAL_PORT) { + // Append the isolate (if it exists). + *stream << "," + << "\"isolate\":"; + AppendIsolateRef(stream, isolate_id, isolate_name); + } + *stream << "}"; +} + +} // namespace + +void PlatformViewServiceProtocol::RegisterHook(bool running_precompiled_code) { + // Listing of FlutterViews. + Dart_RegisterRootServiceRequestCallback(kListViewsExtensionName, &ListViews, + nullptr); + // Screenshot. + Dart_RegisterRootServiceRequestCallback(kScreenshotExtensionName, &Screenshot, + nullptr); + + // SkPicture Screenshot. + Dart_RegisterRootServiceRequestCallback(kScreenshotSkpExtensionName, + &ScreenshotSkp, nullptr); + + // The following set of service protocol extensions require debug build + if (running_precompiled_code) { + return; + } + Dart_RegisterRootServiceRequestCallback(kRunInViewExtensionName, &RunInView, + nullptr); + Dart_RegisterRootServiceRequestCallback(kSetAssetBundlePathExtensionName, + &SetAssetBundlePath, nullptr); + // [benchmark helper] Wait for the UI Thread to idle. + Dart_RegisterRootServiceRequestCallback(kFlushUIThreadTasksExtensionName, + &FlushUIThreadTasks, nullptr); +} + +const char* PlatformViewServiceProtocol::kRunInViewExtensionName = + "_flutter.runInView"; + +bool PlatformViewServiceProtocol::RunInView(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + const char* view_id = + ValueForKey(param_keys, param_values, num_params, "viewId"); + const char* asset_directory = + ValueForKey(param_keys, param_values, num_params, "assetDirectory"); + const char* main_script = + ValueForKey(param_keys, param_values, num_params, "mainScript"); + const char* packages_file = + ValueForKey(param_keys, param_values, num_params, "packagesFile"); + if (view_id == NULL) { + return ErrorMissingParameter(json_object, "viewId"); + } + if (strncmp(view_id, kViewIdPrefx, kViewIdPrefxLength) != 0) { + return ErrorBadParameter(json_object, "viewId", view_id); + } + if (asset_directory == NULL) { + return ErrorMissingParameter(json_object, "assetDirectory"); + } + if (main_script == NULL) { + return ErrorMissingParameter(json_object, "mainScript"); + } + if (packages_file == NULL) { + return ErrorMissingParameter(json_object, "packagesFile"); + } + + // Convert the actual flutter view hex id into a number. + uintptr_t view_id_as_num = + std::stoull((view_id + kViewIdPrefxLength), nullptr, 16); + + // Ask the Shell to run this script in the specified view. This will run a + // task on the UI thread before returning. + Shell& shell = Shell::Shared(); + bool view_existed = false; + Dart_Port main_port = ILLEGAL_PORT; + std::string isolate_name; + shell.RunInPlatformView(view_id_as_num, main_script, packages_file, + asset_directory, &view_existed, &main_port, + &isolate_name); + + if (!view_existed) { + // If the view did not exist this request has definitely failed. + return ErrorUnknownView(json_object, view_id); + } + + // The view existed and the isolate was created. Success. + std::stringstream response; + response << "{\"type\":\"Success\"," + << "\"view\":"; + AppendFlutterView(&response, view_id_as_num, main_port, isolate_name); + response << "}"; + *json_object = strdup(response.str().c_str()); + return true; +} + +const char* PlatformViewServiceProtocol::kListViewsExtensionName = + "_flutter.listViews"; + +bool PlatformViewServiceProtocol::ListViews(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + std::stringstream response; + response << "{\"type\":\"FlutterViewList\",\"views\":["; + bool prefix_comma = false; + Shell::Shared().IteratePlatformViews( + [&response, &prefix_comma](PlatformView* view) -> bool { + if (prefix_comma) { + response << ','; + } else { + prefix_comma = true; + } + AppendFlutterView(&response, reinterpret_cast(view), + view->engine().GetUIIsolateMainPort(), + view->engine().GetUIIsolateName()); + return true; + }); + response << "]}"; + // Copy the response. + *json_object = strdup(response.str().c_str()); + return true; +} + +const char* PlatformViewServiceProtocol::kScreenshotExtensionName = + "_flutter.screenshot"; + +static sk_sp EncodeBitmapAsPNG(const SkBitmap& bitmap) { + return SkEncodeBitmap(bitmap, SkEncodedImageFormat::kPNG, 100); +} + +static fml::WeakPtr GetRandomRasterizer() { + fml::WeakPtr rasterizer; + Shell::Shared().IteratePlatformViews( + [&rasterizer](PlatformView* view) -> bool { + rasterizer = view->rasterizer().GetWeakRasterizerPtr(); + // We just grab the first rasterizer so there is no need to iterate + // further. + return false; + }); + return rasterizer; +} + +bool PlatformViewServiceProtocol::Screenshot(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + fxl::AutoResetWaitableEvent latch; + SkBitmap bitmap; + blink::Threads::Gpu()->PostTask([&latch, &bitmap]() { + ScreenshotGpuTask(&bitmap); + latch.Signal(); + }); + + latch.Wait(); + + sk_sp png(EncodeBitmapAsPNG(bitmap)); + + if (!png) + return ErrorServer(json_object, "can not encode screenshot"); + + size_t b64_size = SkBase64::Encode(png->data(), png->size(), nullptr); + SkAutoTMalloc b64_data(b64_size); + SkBase64::Encode(png->data(), png->size(), b64_data.get()); + + std::stringstream response; + response << "{\"type\":\"Screenshot\"," + << "\"screenshot\":\"" << std::string{b64_data.get(), b64_size} + << "\"}"; + *json_object = strdup(response.str().c_str()); + return true; +} + +void PlatformViewServiceProtocol::ScreenshotGpuTask(SkBitmap* bitmap) { + auto rasterizer = GetRandomRasterizer(); + + if (!rasterizer) + return; + + flow::LayerTree* layer_tree = rasterizer->GetLastLayerTree(); + if (layer_tree == nullptr) + return; + + const SkISize& frame_size = layer_tree->frame_size(); + if (!bitmap->tryAllocN32Pixels(frame_size.width(), frame_size.height())) + return; + + sk_sp surface = SkSurface::MakeRasterDirect( + bitmap->info(), bitmap->getPixels(), bitmap->rowBytes()); + + flow::CompositorContext compositor_context(nullptr); + SkCanvas* canvas = surface->getCanvas(); + flow::CompositorContext::ScopedFrame frame = + compositor_context.AcquireFrame(nullptr, canvas, false); + + canvas->clear(SK_ColorBLACK); + layer_tree->Raster(frame); + canvas->flush(); +} + +const char* PlatformViewServiceProtocol::kScreenshotSkpExtensionName = + "_flutter.screenshotSkp"; + +bool PlatformViewServiceProtocol::ScreenshotSkp(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + fxl::AutoResetWaitableEvent latch; + sk_sp picture; + blink::Threads::Gpu()->PostTask([&latch, &picture]() { + picture = ScreenshotSkpGpuTask(); + latch.Signal(); + }); + + latch.Wait(); + + sk_sp skp_data = picture->serialize(); + + size_t b64_size = + SkBase64::Encode(skp_data->data(), skp_data->size(), nullptr); + SkAutoTMalloc b64_data(b64_size); + SkBase64::Encode(skp_data->data(), skp_data->size(), b64_data.get()); + + std::stringstream response; + response << "{\"type\":\"ScreenshotSkp\"," + << "\"skp\":\"" << std::string{b64_data.get(), b64_size} << "\"}"; + *json_object = strdup(response.str().c_str()); + return true; +} + +sk_sp PlatformViewServiceProtocol::ScreenshotSkpGpuTask() { + auto rasterizer = GetRandomRasterizer(); + + if (!rasterizer) + return nullptr; + + flow::LayerTree* layer_tree = rasterizer->GetLastLayerTree(); + if (layer_tree == nullptr) + return nullptr; + + SkPictureRecorder recorder; + recorder.beginRecording(SkRect::MakeWH(layer_tree->frame_size().width(), + layer_tree->frame_size().height())); + + flow::CompositorContext compositor_context(nullptr); + flow::CompositorContext::ScopedFrame frame = compositor_context.AcquireFrame( + nullptr, recorder.getRecordingCanvas(), false); + layer_tree->Raster(frame); + + return recorder.finishRecordingAsPicture(); +} + +const char* PlatformViewServiceProtocol::kFlushUIThreadTasksExtensionName = + "_flutter.flushUIThreadTasks"; + +// This API should not be invoked by production code. +// It can potentially starve the service isolate if the main isolate pauses +// at a breakpoint or is in an infinite loop. +// +// It should be invoked from the VM Service and and blocks it until UI thread +// tasks are processed. +bool PlatformViewServiceProtocol::FlushUIThreadTasks(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + fxl::AutoResetWaitableEvent latch; + blink::Threads::UI()->PostTask([&latch]() { + // This task is empty because we just need to synchronize this RPC with the + // UI Thread + latch.Signal(); + }); + + latch.Wait(); + + *json_object = strdup("{\"type\":\"Success\"}"); + return true; +} + +const char* PlatformViewServiceProtocol::kSetAssetBundlePathExtensionName = + "_flutter.setAssetBundlePath"; + +bool PlatformViewServiceProtocol::SetAssetBundlePath(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object) { + const char* view_id = + ValueForKey(param_keys, param_values, num_params, "viewId"); + if (view_id == nullptr) { + return ErrorMissingParameter(json_object, "viewId"); + } + if (strncmp(view_id, kViewIdPrefx, kViewIdPrefxLength) != 0) { + return ErrorBadParameter(json_object, "viewId", view_id); + } + const char* asset_directory = + ValueForKey(param_keys, param_values, num_params, "assetDirectory"); + if (asset_directory == nullptr) { + return ErrorMissingParameter(json_object, "assetDirectory"); + } + + // Convert the actual flutter view hex id into a number. + uintptr_t view_id_as_num = + std::stoull((view_id + kViewIdPrefxLength), nullptr, 16); + + // Ask the Shell to update asset bundle path in the specified view. + // This will run a task on the UI thread before returning. + Shell& shell = Shell::Shared(); + bool view_existed = false; + Dart_Port main_port = ILLEGAL_PORT; + std::string isolate_name; + shell.SetAssetBundlePathInPlatformView(view_id_as_num, asset_directory, + &view_existed, &main_port, + &isolate_name); + + if (!view_existed) { + // If the view did not exist this request has definitely failed. + return ErrorUnknownView(json_object, view_id); + } + + // The view existed and the isolate was created. Success. + std::stringstream response; + response << "{\"type\":\"Success\"," + << "\"view\":"; + AppendFlutterView(&response, view_id_as_num, main_port, isolate_name); + response << "}"; + *json_object = strdup(response.str().c_str()); + return true; +} + +} // namespace shell diff --git a/shell/common/platform_view_service_protocol.h b/shell/common/platform_view_service_protocol.h new file mode 100644 index 0000000000000..b7f74b56a08ba --- /dev/null +++ b/shell/common/platform_view_service_protocol.h @@ -0,0 +1,85 @@ +// Copyright 2016 The Chromium 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 SHELL_COMMON_VIEW_SERVICE_PROTOCOL_H_ +#define SHELL_COMMON_VIEW_SERVICE_PROTOCOL_H_ + +#include + +#include "flutter/shell/common/platform_view.h" +#include "lib/fxl/synchronization/waitable_event.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" +#include "third_party/skia/include/core/SkBitmap.h" + +namespace shell { + +class PlatformViewServiceProtocol { + public: + static void RegisterHook(bool running_precompiled_code); + + private: + static const char* kRunInViewExtensionName; + // It should be invoked from the VM Service and and blocks it until previous + // UI thread tasks are processed. + static bool RunInView(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + + static const char* kListViewsExtensionName; + static bool ListViews(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + + static const char* kScreenshotExtensionName; + // It should be invoked from the VM Service and and blocks it until previous + // GPU thread tasks are processed. + static bool Screenshot(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + static void ScreenshotGpuTask(SkBitmap* bitmap); + + static const char* kScreenshotSkpExtensionName; + static bool ScreenshotSkp(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + static sk_sp ScreenshotSkpGpuTask(); + + // This API should not be invoked by production code. + // It can potentially starve the service isolate if the main isolate pauses + // at a breakpoint or is in an infinite loop. + // + // It should be invoked from the VM Service and and blocks it until previous + // GPU thread tasks are processed. + static const char* kFlushUIThreadTasksExtensionName; + static bool FlushUIThreadTasks(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); + + static const char* kSetAssetBundlePathExtensionName; + static bool SetAssetBundlePath(const char* method, + const char** param_keys, + const char** param_values, + intptr_t num_params, + void* user_data, + const char** json_object); +}; + +} // namespace shell + +#endif // SHELL_COMMON_VIEW_SERVICE_PROTOCOL_H_ diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 5a519b3efea26..905ee6285c5d3 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -4,205 +4,8 @@ #include "flutter/shell/common/rasterizer.h" -#include - -#include "third_party/skia/include/core/SkEncodedImageFormat.h" -#include "third_party/skia/include/core/SkImageEncoder.h" -#include "third_party/skia/include/core/SkPictureRecorder.h" -#include "third_party/skia/include/core/SkSurface.h" -#include "third_party/skia/src/utils/SkBase64.h" - namespace shell { -Rasterizer::Rasterizer(blink::TaskRunners task_runners) - : task_runners_(std::move(task_runners)), weak_factory_(this) { - weak_prototype_ = weak_factory_.GetWeakPtr(); -} - Rasterizer::~Rasterizer() = default; -fml::WeakPtr Rasterizer::GetWeakPtr() const { - return weak_prototype_; -} - -void Rasterizer::Setup(std::unique_ptr surface) { - surface_ = std::move(surface); -} - -void Rasterizer::Teardown() { - surface_.reset(); - last_layer_tree_.reset(); -} - -flow::TextureRegistry* Rasterizer::GetTextureRegistry() { - if (!surface_) { - return nullptr; - } - - return &(surface_->GetCompositorContext().texture_registry()); -} - -flow::LayerTree* Rasterizer::GetLastLayerTree() { - return last_layer_tree_.get(); -} - -void Rasterizer::DrawLastLayerTree() { - if (!last_layer_tree_ || !surface_) { - return; - } - DrawToSurface(*last_layer_tree_); -} - -void Rasterizer::Draw( - fxl::RefPtr> pipeline) { - TRACE_EVENT0("flutter", "GPURasterizer::Draw"); - - flutter::Pipeline::Consumer consumer = - std::bind(&Rasterizer::DoDraw, this, std::placeholders::_1); - - // Consume as many pipeline items as possible. But yield the event loop - // between successive tries. - switch (pipeline->Consume(consumer)) { - case flutter::PipelineConsumeResult::MoreAvailable: { - task_runners_.GetGPUTaskRunner()->PostTask( - [weak_this = weak_factory_.GetWeakPtr(), pipeline]() { - if (weak_this) { - weak_this->Draw(pipeline); - } - }); - break; - } - default: - break; - } -} - -void Rasterizer::DoDraw(std::unique_ptr layer_tree) { - if (!layer_tree || !surface_) { - return; - } - - if (DrawToSurface(*layer_tree)) { - last_layer_tree_ = std::move(layer_tree); - } -} - -bool Rasterizer::DrawToSurface(flow::LayerTree& layer_tree) { - FXL_DCHECK(surface_); - - auto frame = surface_->AcquireFrame(layer_tree.frame_size()); - - if (frame == nullptr) { - return false; - } - - auto& compositor_context = surface_->GetCompositorContext(); - - // There is no way for the compositor to know how long the layer tree - // construction took. Fortunately, the layer tree does. Grab that time - // for instrumentation. - compositor_context.engine_time().SetLapTime(layer_tree.construction_time()); - - auto compositor_frame = compositor_context.AcquireFrame( - surface_->GetContext(), frame->SkiaCanvas(), true); - - if (compositor_frame && compositor_frame->Raster(layer_tree, false)) { - frame->Submit(); - FireNextFrameCallbackIfPresent(); - return true; - } - - return false; -} - -static sk_sp ScreenshotLayerTreeAsPicture(flow::LayerTree* tree) { - FXL_DCHECK(tree != nullptr); - SkPictureRecorder recorder; - recorder.beginRecording( - SkRect::MakeWH(tree->frame_size().width(), tree->frame_size().height())); - - flow::CompositorContext compositor_context; - auto frame = compositor_context.AcquireFrame( - nullptr, recorder.getRecordingCanvas(), false); - - frame->Raster(*tree, true); - - return recorder.finishRecordingAsPicture(); -} - -static sk_sp ScreenshotLayerTreeAsImage(flow::LayerTree* tree, - bool compressed) { - const SkISize& frame_size = tree->frame_size(); - SkBitmap bitmap; - if (!bitmap.tryAllocN32Pixels(frame_size.width(), frame_size.height())) { - return nullptr; - } - auto bitmap_surface = SkSurface::MakeRasterDirect( - bitmap.info(), bitmap.getPixels(), bitmap.rowBytes()); - flow::CompositorContext compositor_context; - auto canvas = bitmap_surface->getCanvas(); - auto frame = compositor_context.AcquireFrame(nullptr, canvas, false); - canvas->clear(SK_ColorBLACK); - frame->Raster(*tree, true); - canvas->flush(); - if (compressed) { - return SkEncodeBitmap(bitmap, SkEncodedImageFormat::kPNG, 100); - } else { - return SkData::MakeWithCopy(bitmap.getPixels(), bitmap.computeByteSize()); - } - return nullptr; -} - -Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree( - Rasterizer::ScreenshotType type, - bool base64_encode) { - auto layer_tree = GetLastLayerTree(); - if (layer_tree == nullptr) { - FXL_DLOG(INFO) << "Last layer tree was null when screenshotting."; - return {}; - } - - sk_sp data = nullptr; - - switch (type) { - case ScreenshotType::SkiaPicture: - data = ScreenshotLayerTreeAsPicture(layer_tree)->serialize(); - break; - case ScreenshotType::UncompressedImage: - data = ScreenshotLayerTreeAsImage(layer_tree, false); - break; - case ScreenshotType::CompressedImage: - data = ScreenshotLayerTreeAsImage(layer_tree, true); - break; - } - - if (data == nullptr) { - FXL_DLOG(INFO) << "Sceenshot data was null."; - return {}; - } - - if (base64_encode) { - size_t b64_size = SkBase64::Encode(data->data(), data->size(), nullptr); - auto b64_data = SkData::MakeUninitialized(b64_size); - SkBase64::Encode(data->data(), data->size(), b64_data->writable_data()); - return Rasterizer::Screenshot{b64_data, layer_tree->frame_size()}; - } - - return Rasterizer::Screenshot{data, layer_tree->frame_size()}; -} - -void Rasterizer::SetNextFrameCallback(fxl::Closure callback) { - next_frame_callback_ = callback; -} - -void Rasterizer::FireNextFrameCallbackIfPresent() { - if (!next_frame_callback_) { - return; - } - // It is safe for the callback to set a new callback. - auto callback = next_frame_callback_; - next_frame_callback_ = nullptr; - callback(); -} - } // namespace shell diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 908717b74c168..6f45f49d8178a 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -7,7 +7,6 @@ #include -#include "flutter/common/task_runners.h" #include "flutter/flow/layers/layer_tree.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/surface.h" @@ -17,64 +16,34 @@ namespace shell { -class Rasterizer final { +class Rasterizer { public: - Rasterizer(blink::TaskRunners task_runners); + virtual ~Rasterizer(); - ~Rasterizer(); + virtual void Setup(std::unique_ptr surface_or_null, + fxl::Closure rasterizer_continuation, + fxl::AutoResetWaitableEvent* setup_completion_event) = 0; - void Setup(std::unique_ptr surface); + virtual void Teardown( + fxl::AutoResetWaitableEvent* teardown_completion_event) = 0; - void Teardown(); + virtual void Clear(SkColor color, const SkISize& size) = 0; - fml::WeakPtr GetWeakPtr() const; + virtual fml::WeakPtr GetWeakRasterizerPtr() = 0; - flow::LayerTree* GetLastLayerTree(); + virtual flow::LayerTree* GetLastLayerTree() = 0; - void DrawLastLayerTree(); + virtual void DrawLastLayerTree() = 0; - flow::TextureRegistry* GetTextureRegistry(); + virtual flow::TextureRegistry& GetTextureRegistry() = 0; - void Draw(fxl::RefPtr> pipeline); + virtual void Draw( + fxl::RefPtr> pipeline) = 0; - enum class ScreenshotType { - SkiaPicture, - UncompressedImage, // In kN32_SkColorType format - CompressedImage, - }; + // Set a callback to be called once when the next frame is drawn. + virtual void AddNextFrameCallback(fxl::Closure nextFrameCallback) = 0; - struct Screenshot { - sk_sp data; - SkISize frame_size = SkISize::MakeEmpty(); - - Screenshot() {} - - Screenshot(sk_sp p_data, SkISize p_size) - : data(std::move(p_data)), frame_size(p_size) {} - }; - - Screenshot ScreenshotLastLayerTree(ScreenshotType type, bool base64_encode); - - // Sets a callback that will be executed after the next frame is submitted to - // the surface on the GPU task runner. - void SetNextFrameCallback(fxl::Closure callback); - - private: - blink::TaskRunners task_runners_; - std::unique_ptr surface_; - std::unique_ptr compositor_context_; - std::unique_ptr last_layer_tree_; - fxl::Closure next_frame_callback_; - fml::WeakPtr weak_prototype_; - fml::WeakPtrFactory weak_factory_; - - void DoDraw(std::unique_ptr layer_tree); - - bool DrawToSurface(flow::LayerTree& layer_tree); - - void FireNextFrameCallbackIfPresent(); - - FXL_DISALLOW_COPY_AND_ASSIGN(Rasterizer); + virtual void SetTextureRegistry(flow::TextureRegistry* textureRegistry) = 0; }; } // namespace shell diff --git a/shell/common/run_configuration.cc b/shell/common/run_configuration.cc deleted file mode 100644 index 7fb385fb4d9dc..0000000000000 --- a/shell/common/run_configuration.cc +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/shell/common/run_configuration.h" - -#include - -#include "flutter/assets/directory_asset_bundle.h" -#include "flutter/assets/zip_asset_store.h" -#include "flutter/fml/file.h" -#include "flutter/runtime/dart_vm.h" - -namespace shell { - -RunConfiguration RunConfiguration::InferFromSettings( - const blink::Settings& settings) { - auto asset_manager = fxl::MakeRefCounted(); - - asset_manager->PushBack(std::make_unique( - fml::Duplicate(settings.assets_dir))); - - asset_manager->PushBack( - std::make_unique(fml::OpenFile( - settings.assets_path.c_str(), fml::OpenPermission::kRead, true))); - - asset_manager->PushBack( - std::make_unique(settings.flx_path)); - - return {IsolateConfiguration::InferFromSettings(settings, asset_manager), - asset_manager}; -} - -RunConfiguration::RunConfiguration( - std::unique_ptr configuration) - : RunConfiguration(std::move(configuration), - fxl::MakeRefCounted()) {} - -RunConfiguration::RunConfiguration( - std::unique_ptr configuration, - fxl::RefPtr asset_manager) - : isolate_configuration_(std::move(configuration)), - asset_manager_(std::move(asset_manager)) {} - -RunConfiguration::RunConfiguration(RunConfiguration&&) = default; - -RunConfiguration::~RunConfiguration() = default; - -bool RunConfiguration::IsValid() const { - return asset_manager_ && isolate_configuration_; -} - -bool RunConfiguration::AddAssetResolver( - std::unique_ptr resolver) { - if (!resolver || !resolver->IsValid()) { - return false; - } - - asset_manager_->PushBack(std::move(resolver)); - return true; -} - -void RunConfiguration::SetEntrypoint(std::string entrypoint) { - entrypoint_ = std::move(entrypoint); -} - -fxl::RefPtr RunConfiguration::GetAssetManager() const { - return asset_manager_; -} - -const std::string& RunConfiguration::GetEntrypoint() const { - return entrypoint_; -} - -std::unique_ptr -RunConfiguration::TakeIsolateConfiguration() { - return std::move(isolate_configuration_); -} - -} // namespace shell diff --git a/shell/common/run_configuration.h b/shell/common/run_configuration.h deleted file mode 100644 index 59aa07566685c..0000000000000 --- a/shell/common/run_configuration.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2017 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_COMMON_RUN_CONFIGURATION_H_ -#define FLUTTER_SHELL_COMMON_RUN_CONFIGURATION_H_ - -#include -#include - -#include "flutter/assets/asset_manager.h" -#include "flutter/assets/asset_resolver.h" -#include "flutter/common/settings.h" -#include "flutter/fml/mapping.h" -#include "flutter/shell/common/isolate_configuration.h" -#include "lib/fxl/files/unique_fd.h" -#include "lib/fxl/macros.h" - -namespace shell { - -class RunConfiguration { - public: - static RunConfiguration InferFromSettings(const blink::Settings& settings); - - RunConfiguration(std::unique_ptr configuration); - - RunConfiguration(std::unique_ptr configuration, - fxl::RefPtr asset_manager); - - RunConfiguration(RunConfiguration&&); - - ~RunConfiguration(); - - bool IsValid() const; - - bool AddAssetResolver(std::unique_ptr resolver); - - void SetEntrypoint(std::string entrypoint); - - fxl::RefPtr GetAssetManager() const; - - const std::string& GetEntrypoint() const; - - std::unique_ptr TakeIsolateConfiguration(); - - private: - std::unique_ptr isolate_configuration_; - fxl::RefPtr asset_manager_; - std::string entrypoint_ = "main"; - - FXL_DISALLOW_COPY_AND_ASSIGN(RunConfiguration); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_COMMON_RUN_CONFIGURATION_H_ diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 53527a996bd76..14f8fee84bb5f 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -2,859 +2,362 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define RAPIDJSON_HAS_STDSTRING 1 - #include "flutter/shell/common/shell.h" +#include #include #include #include -#include "flutter/assets/directory_asset_bundle.h" -#include "flutter/fml/file.h" +#include "flutter/common/settings.h" +#include "flutter/common/threads.h" #include "flutter/fml/icu_util.h" #include "flutter/fml/message_loop.h" -#include "flutter/glue/trace_event.h" -#include "flutter/runtime/dart_vm.h" +#include "flutter/fml/trace_event.h" +#include "flutter/runtime/dart_init.h" #include "flutter/shell/common/engine.h" +#include "flutter/shell/common/platform_view_service_protocol.h" #include "flutter/shell/common/skia_event_tracer_impl.h" #include "flutter/shell/common/switches.h" -#include "flutter/shell/common/vsync_waiter.h" #include "lib/fxl/files/unique_fd.h" -#include "lib/fxl/functional/make_copyable.h" -#include "lib/fxl/logging.h" #include "third_party/dart/runtime/include/dart_tools_api.h" #include "third_party/skia/include/core/SkGraphics.h" namespace shell { +namespace { -std::unique_ptr Shell::CreateShellOnPlatformThread( - blink::TaskRunners task_runners, - blink::Settings settings, - Shell::CreateCallback on_create_platform_view, - Shell::CreateCallback on_create_rasterizer) { - if (!task_runners.IsValid()) { - return nullptr; - } - - auto shell = std::unique_ptr(new Shell(task_runners, settings)); - - // Create the platform view on the platform thread (this thread). - auto platform_view = on_create_platform_view(*shell.get()); - if (!platform_view || !platform_view->GetWeakPtr()) { - return nullptr; - } - - // Ask the platform view for the vsync waiter. This will be used by the engine - // to create the animator. - auto vsync_waiter = platform_view->CreateVSyncWaiter(); - if (!vsync_waiter) { - return nullptr; - } - - // Create the IO manager on the IO thread. The IO manager must be initialized - // first because it has state that the other subsystems depend on. It must - // first be booted and the necessary references obtained to initialize the - // other subsystems. - fxl::AutoResetWaitableEvent io_latch; - std::unique_ptr io_manager; - fml::WeakPtr resource_context; - fxl::RefPtr unref_queue; - auto io_task_runner = shell->GetTaskRunners().GetIOTaskRunner(); - fml::TaskRunner::RunNowOrPostTask( - io_task_runner, - [&io_latch, // - &io_manager, // - &resource_context, // - &unref_queue, // - &platform_view, // - io_task_runner // - ]() { - io_manager = std::make_unique( - platform_view->CreateResourceContext(), io_task_runner); - resource_context = io_manager->GetResourceContext(); - unref_queue = io_manager->GetSkiaUnrefQueue(); - io_latch.Signal(); - }); - io_latch.Wait(); - - // Create the rasterizer on the GPU thread. - fxl::AutoResetWaitableEvent gpu_latch; - std::unique_ptr rasterizer; - fml::TaskRunner::RunNowOrPostTask( - task_runners.GetGPUTaskRunner(), [&gpu_latch, // - &rasterizer, // - on_create_rasterizer, // - shell = shell.get() // - ]() { - if (auto new_rasterizer = on_create_rasterizer(*shell)) { - rasterizer = std::move(new_rasterizer); - } - gpu_latch.Signal(); - }); - - // Create the engine on the UI thread. - fxl::AutoResetWaitableEvent ui_latch; - std::unique_ptr engine; - fml::TaskRunner::RunNowOrPostTask( - shell->GetTaskRunners().GetUITaskRunner(), - fxl::MakeCopyable([&ui_latch, // - &engine, // - shell = shell.get(), // - vsync_waiter = std::move(vsync_waiter), // - resource_context = std::move(resource_context), // - unref_queue = std::move(unref_queue) // - ]() mutable { - const auto& task_runners = shell->GetTaskRunners(); - - // The animator is owned by the UI thread but it gets its vsync pulses - // from the platform. - auto animator = std::make_unique(*shell, task_runners, - std::move(vsync_waiter)); - - engine = std::make_unique(*shell, // - shell->GetDartVM(), // - task_runners, // - shell->GetSettings(), // - std::move(animator), // - std::move(resource_context), // - std::move(unref_queue) // - ); - ui_latch.Signal(); - })); - - gpu_latch.Wait(); - ui_latch.Wait(); - // We are already on the platform thread. So there is no platform latch to - // wait on. - - if (!shell->Setup(std::move(platform_view), // - std::move(engine), // - std::move(rasterizer), // - std::move(io_manager)) // - ) { - return nullptr; - } - - return shell; -} - -std::unique_ptr Shell::Create( - blink::TaskRunners task_runners, - blink::Settings settings, - Shell::CreateCallback on_create_platform_view, - Shell::CreateCallback on_create_rasterizer) { - if (!task_runners.IsValid() || !on_create_platform_view || - !on_create_rasterizer) { - return nullptr; - } - - fxl::AutoResetWaitableEvent latch; - std::unique_ptr shell; - fml::TaskRunner::RunNowOrPostTask( - task_runners.GetPlatformTaskRunner(), - [&latch, &shell, task_runners = std::move(task_runners), settings, - on_create_platform_view, on_create_rasterizer]() { - shell = CreateShellOnPlatformThread(std::move(task_runners), settings, - on_create_platform_view, - on_create_rasterizer); - latch.Signal(); - }); - latch.Wait(); - return shell; -} - -Shell::Shell(blink::TaskRunners task_runners, blink::Settings settings) - : task_runners_(std::move(task_runners)), - settings_(std::move(settings)), - vm_(blink::DartVM::ForProcess(settings_)) { - FXL_DCHECK(task_runners_.IsValid()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - - if (settings_.icu_data_path.size() != 0) { - fml::icu::InitializeICU(settings_.icu_data_path); - } else { - FXL_DLOG(WARNING) << "Skipping ICU initialization in the shell."; - } - - if (settings_.trace_skia) { - InitSkiaEventTracer(settings_.trace_skia); - } +static Shell* g_shell = nullptr; - if (!settings_.skia_deterministic_rendering_on_cpu) { - SkGraphics::Init(); - } else { - FXL_DLOG(INFO) << "Skia deterministic rendering is enabled."; - } +template +bool GetSwitchValue(const fxl::CommandLine& command_line, + Switch sw, + T* result) { + std::string switch_string; - // Install service protocol handlers. - - service_protocol_handlers_[blink::ServiceProtocol::kScreenshotExtensionName - .ToString()] = { - task_runners_.GetGPUTaskRunner(), - std::bind(&Shell::OnServiceProtocolScreenshot, this, - std::placeholders::_1, std::placeholders::_2)}; - service_protocol_handlers_[blink::ServiceProtocol::kScreenshotSkpExtensionName - .ToString()] = { - task_runners_.GetGPUTaskRunner(), - std::bind(&Shell::OnServiceProtocolScreenshotSKP, this, - std::placeholders::_1, std::placeholders::_2)}; - service_protocol_handlers_[blink::ServiceProtocol::kRunInViewExtensionName - .ToString()] = { - task_runners_.GetUITaskRunner(), - std::bind(&Shell::OnServiceProtocolRunInView, this, std::placeholders::_1, - std::placeholders::_2)}; - service_protocol_handlers_ - [blink::ServiceProtocol::kFlushUIThreadTasksExtensionName.ToString()] = { - task_runners_.GetUITaskRunner(), - std::bind(&Shell::OnServiceProtocolFlushUIThreadTasks, this, - std::placeholders::_1, std::placeholders::_2)}; - service_protocol_handlers_ - [blink::ServiceProtocol::kSetAssetBundlePathExtensionName.ToString()] = { - task_runners_.GetUITaskRunner(), - std::bind(&Shell::OnServiceProtocolSetAssetBundlePath, this, - std::placeholders::_1, std::placeholders::_2)}; -} - -Shell::~Shell() { - if (auto vm = blink::DartVM::ForProcessIfInitialized()) { - vm->GetServiceProtocol().RemoveHandler(this); - } - - fxl::AutoResetWaitableEvent ui_latch, gpu_latch, platform_latch, io_latch; - - fml::TaskRunner::RunNowOrPostTask( - task_runners_.GetUITaskRunner(), - fxl::MakeCopyable([engine = std::move(engine_), &ui_latch]() mutable { - engine.reset(); - ui_latch.Signal(); - })); - ui_latch.Wait(); - - fml::TaskRunner::RunNowOrPostTask( - task_runners_.GetGPUTaskRunner(), - fxl::MakeCopyable( - [rasterizer = std::move(rasterizer_), &gpu_latch]() mutable { - rasterizer.reset(); - gpu_latch.Signal(); - })); - gpu_latch.Wait(); - - fml::TaskRunner::RunNowOrPostTask( - task_runners_.GetIOTaskRunner(), - fxl::MakeCopyable( - [io_manager = std::move(io_manager_), &io_latch]() mutable { - io_manager.reset(); - io_latch.Signal(); - })); - - io_latch.Wait(); - - // The platform view must go last because it may be holding onto platform side - // counterparts to resources owned by subsystems running on other threads. For - // example, the NSOpenGLContext on the Mac. - fml::TaskRunner::RunNowOrPostTask( - task_runners_.GetPlatformTaskRunner(), - fxl::MakeCopyable([platform_view = std::move(platform_view_), - &platform_latch]() mutable { - platform_view.reset(); - platform_latch.Signal(); - })); - platform_latch.Wait(); -} - -bool Shell::IsSetup() const { - return is_setup_; -} - -bool Shell::Setup(std::unique_ptr platform_view, - std::unique_ptr engine, - std::unique_ptr rasterizer, - std::unique_ptr io_manager) { - if (is_setup_) { + if (!command_line.GetOptionValue(FlagForSwitch(sw), &switch_string)) { return false; } - if (!platform_view || !engine || !rasterizer || !io_manager) { - return false; - } - - platform_view_ = std::move(platform_view); - engine_ = std::move(engine); - rasterizer_ = std::move(rasterizer); - io_manager_ = std::move(io_manager); - - is_setup_ = true; - - if (auto vm = blink::DartVM::ForProcessIfInitialized()) { - vm->GetServiceProtocol().AddHandler(this); + std::stringstream stream(switch_string); + T value = 0; + if (stream >> value) { + *result = value; + return true; } - return true; + return false; } -const blink::Settings& Shell::GetSettings() const { - return settings_; -} +} // namespace -const blink::TaskRunners& Shell::GetTaskRunners() const { - return task_runners_; -} +Shell::Shell(fxl::CommandLine command_line) + : command_line_(std::move(command_line)) { + FXL_DCHECK(!g_shell); -fml::WeakPtr Shell::GetRasterizer() { - FXL_DCHECK(is_setup_); - return rasterizer_->GetWeakPtr(); -} + gpu_thread_.reset(new fml::Thread("gpu_thread")); + ui_thread_.reset(new fml::Thread("ui_thread")); + io_thread_.reset(new fml::Thread("io_thread")); -fml::WeakPtr Shell::GetEngine() { - FXL_DCHECK(is_setup_); - return engine_->GetWeakPtr(); -} + // Since we are not using fml::Thread, we need to initialize the message loop + // manually. + fml::MessageLoop::EnsureInitializedForCurrentThread(); + blink::Threads threads(fml::MessageLoop::GetCurrent().GetTaskRunner(), + gpu_thread_->GetTaskRunner(), + ui_thread_->GetTaskRunner(), + io_thread_->GetTaskRunner()); + blink::Threads::Set(threads); -fml::WeakPtr Shell::GetPlatformView() { - FXL_DCHECK(is_setup_); - return platform_view_->GetWeakPtr(); -} + blink::Threads::Gpu()->PostTask([this]() { InitGpuThread(); }); + blink::Threads::UI()->PostTask([this]() { InitUIThread(); }); -const blink::DartVM& Shell::GetDartVM() const { - return *vm_; + blink::SetRegisterNativeServiceProtocolExtensionHook( + PlatformViewServiceProtocol::RegisterHook); } -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewCreated(const PlatformView& view, - std::unique_ptr surface) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); +Shell::~Shell() {} - // Note: - // This is a synchronous operation because certain platforms depend on - // setup/suspension of all activities that may be interacting with the GPU in - // a synchronous fashion. +void Shell::InitStandalone(fxl::CommandLine command_line, + std::string icu_data_path, + std::string application_library_path, + std::string bundle_path) { + TRACE_EVENT0("flutter", "Shell::InitStandalone"); - fxl::AutoResetWaitableEvent latch; - auto gpu_task = fxl::MakeCopyable([rasterizer = rasterizer_->GetWeakPtr(), // - surface = std::move(surface), // - &latch]() mutable { - if (rasterizer) { - rasterizer->Setup(std::move(surface)); - } - // Step 2: All done. Signal the latch that the platform thread is waiting - // on. - latch.Signal(); - }); + fml::icu::InitializeICU(icu_data_path); - auto ui_task = [engine = engine_->GetWeakPtr(), // - gpu_task_runner = task_runners_.GetGPUTaskRunner(), // - gpu_task // - ] { - if (engine) { - engine->OnOutputSurfaceCreated(); - } - // Step 1: Next, tell the GPU thread that it should create a surface for its - // rasterizer. - fml::TaskRunner::RunNowOrPostTask(gpu_task_runner, gpu_task); - }; - - // Step 0: Post a task onto the UI thread to tell the engine that it has an - // output surface. - fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task); - latch.Wait(); -} - -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewDestroyed(const PlatformView& view) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + if (!command_line.HasOption( + FlagForSwitch(Switch::SkiaDeterministicRendering))) + SkGraphics::Init(); - // Note: - // This is a synchronous operation because certain platforms depend on - // setup/suspension of all activities that may be interacting with the GPU in - // a synchronous fashion. + blink::Settings settings; + settings.application_library_path = application_library_path; - fxl::AutoResetWaitableEvent latch; + // Enable Observatory + settings.enable_observatory = + !command_line.HasOption(FlagForSwitch(Switch::DisableObservatory)); - auto gpu_task = [rasterizer = rasterizer_->GetWeakPtr(), &latch]() { - if (rasterizer) { - rasterizer->Teardown(); + // Set Observatory Port + if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryPort))) { + if (!GetSwitchValue(command_line, Switch::DeviceObservatoryPort, + &settings.observatory_port)) { + FXL_LOG(INFO) + << "Observatory port specified was malformed. Will default to " + << settings.observatory_port; } - // Step 2: All done. Signal the latch that the platform thread is waiting - // on. - latch.Signal(); - }; - - auto ui_task = [engine = engine_->GetWeakPtr(), - gpu_task_runner = task_runners_.GetGPUTaskRunner(), - gpu_task]() { - if (engine) { - engine->OnOutputSurfaceDestroyed(); - } - // Step 1: Next, tell the GPU thread that its rasterizer should suspend - // access to the underlying surface. - fml::TaskRunner::RunNowOrPostTask(gpu_task_runner, gpu_task); - }; - - // Step 0: Post a task onto the UI thread to tell the engine that its output - // surface is about to go away. - fml::TaskRunner::RunNowOrPostTask(task_runners_.GetUITaskRunner(), ui_task); - latch.Wait(); -} - -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewSetViewportMetrics( - const PlatformView& view, - const blink::ViewportMetrics& metrics) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - - task_runners_.GetUITaskRunner()->PostTask( - [engine = engine_->GetWeakPtr(), metrics]() { - if (engine) { - engine->SetViewportMetrics(metrics); - } - }); -} - -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewDispatchPlatformMessage( - const PlatformView& view, - fxl::RefPtr message) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - - task_runners_.GetUITaskRunner()->PostTask( - [engine = engine_->GetWeakPtr(), message = std::move(message)] { - if (engine) { - engine->DispatchPlatformMessage(std::move(message)); - } - }); -} + } -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewDispatchPointerDataPacket( - const PlatformView& view, - std::unique_ptr packet) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - task_runners_.GetUITaskRunner()->PostTask(fxl::MakeCopyable( - [engine = engine_->GetWeakPtr(), packet = std::move(packet)] { - if (engine) { - engine->DispatchPointerDataPacket(*packet); - } - })); -} + // Checked mode overrides. + settings.dart_non_checked_mode = + command_line.HasOption(FlagForSwitch(Switch::DartNonCheckedMode)); -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewDispatchSemanticsAction(const PlatformView& view, - int32_t id, - blink::SemanticsAction action, - std::vector args) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - - task_runners_.GetUITaskRunner()->PostTask( - [engine = engine_->GetWeakPtr(), id, action, args = std::move(args)] { - if (engine) { - engine->DispatchSemanticsAction(id, action, std::move(args)); - } - }); -} + settings.ipv6 = command_line.HasOption(FlagForSwitch(Switch::IPv6)); -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewSetSemanticsEnabled(const PlatformView& view, - bool enabled) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - - task_runners_.GetUITaskRunner()->PostTask( - [engine = engine_->GetWeakPtr(), enabled] { - if (engine) { - engine->SetSemanticsEnabled(enabled); - } - }); -} + settings.start_paused = + command_line.HasOption(FlagForSwitch(Switch::StartPaused)); -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewRegisterTexture( - const PlatformView& view, - std::shared_ptr texture) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - - task_runners_.GetGPUTaskRunner()->PostTask( - [rasterizer = rasterizer_->GetWeakPtr(), texture] { - if (rasterizer) { - if (auto registry = rasterizer->GetTextureRegistry()) { - registry->RegisterTexture(texture); - } - } - }); -} + settings.enable_dart_profiling = + command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling)); -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewUnregisterTexture(const PlatformView& view, - int64_t texture_id) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - - task_runners_.GetGPUTaskRunner()->PostTask( - [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { - if (rasterizer) { - if (auto registry = rasterizer->GetTextureRegistry()) { - registry->UnregisterTexture(texture_id); - } - } - }); -} + settings.enable_software_rendering = + command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering)); -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewMarkTextureFrameAvailable(const PlatformView& view, - int64_t texture_id) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); + settings.using_blink = + command_line.HasOption(FlagForSwitch(Switch::EnableBlink)); - // Tell the rasterizer that one of its textures has a new frame available. - task_runners_.GetGPUTaskRunner()->PostTask( - [rasterizer = rasterizer_->GetWeakPtr(), texture_id]() { - auto registry = rasterizer->GetTextureRegistry(); + settings.endless_trace_buffer = + command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer)); - if (!registry) { - return; - } + settings.trace_startup = + command_line.HasOption(FlagForSwitch(Switch::TraceStartup)); - auto texture = registry->GetTexture(texture_id); + command_line.GetOptionValue(FlagForSwitch(Switch::AotSnapshotPath), + &settings.aot_snapshot_path); - if (!texture) { - return; - } + command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotData), + &settings.aot_vm_snapshot_data_filename); - texture->MarkNewFrameAvailable(); - }); + command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotInstructions), + &settings.aot_vm_snapshot_instr_filename); - // Schedule a new frame without having to rebuild the layer tree. - task_runners_.GetUITaskRunner()->PostTask([engine = engine_->GetWeakPtr()]() { - if (engine) { - engine->ScheduleFrame(false); - } - }); -} + command_line.GetOptionValue(FlagForSwitch(Switch::AotIsolateSnapshotData), + &settings.aot_isolate_snapshot_data_filename); -// |shell::PlatformView::Delegate| -void Shell::OnPlatformViewSetNextFrameCallback(const PlatformView& view, - fxl::Closure closure) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(&view == platform_view_.get()); - FXL_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread()); - - task_runners_.GetGPUTaskRunner()->PostTask( - [rasterizer = rasterizer_->GetWeakPtr(), closure = std::move(closure)]() { - if (rasterizer) { - rasterizer->SetNextFrameCallback(std::move(closure)); - } - }); -} + command_line.GetOptionValue(FlagForSwitch(Switch::AotSharedLibraryPath), + &settings.aot_shared_library_path); -// |shell::Animator::Delegate| -void Shell::OnAnimatorBeginFrame(const Animator& animator, - fxl::TimePoint frame_time) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); + command_line.GetOptionValue( + FlagForSwitch(Switch::AotIsolateSnapshotInstructions), + &settings.aot_isolate_snapshot_instr_filename); - if (engine_) { - engine_->BeginFrame(frame_time); - } -} + command_line.GetOptionValue(FlagForSwitch(Switch::CacheDirPath), + &settings.temp_directory_path); -// |shell::Animator::Delegate| -void Shell::OnAnimatorNotifyIdle(const Animator& animator, int64_t deadline) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); + settings.use_test_fonts = + command_line.HasOption(FlagForSwitch(Switch::UseTestFonts)); - if (engine_) { - engine_->NotifyIdle(deadline); + std::string all_dart_flags; + if (command_line.GetOptionValue(FlagForSwitch(Switch::DartFlags), + &all_dart_flags)) { + std::stringstream stream(all_dart_flags); + std::istream_iterator end; + for (std::istream_iterator it(stream); it != end; ++it) + settings.dart_flags.push_back(*it); } -} -// |shell::Animator::Delegate| -void Shell::OnAnimatorDraw( - const Animator& animator, - fxl::RefPtr> pipeline) { - FXL_DCHECK(is_setup_); - - task_runners_.GetGPUTaskRunner()->PostTask( - [rasterizer = rasterizer_->GetWeakPtr(), - pipeline = std::move(pipeline)]() { - if (rasterizer) { - rasterizer->Draw(pipeline); - } - }); -} + command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag); -// |shell::Animator::Delegate| -void Shell::OnAnimatorDrawLastLayerTree(const Animator& animator) { - FXL_DCHECK(is_setup_); + blink::Settings::Set(settings); - task_runners_.GetGPUTaskRunner()->PostTask( - [rasterizer = rasterizer_->GetWeakPtr()]() { - if (rasterizer) { - rasterizer->DrawLastLayerTree(); - } - }); + Init(std::move(command_line), bundle_path); } -// |shell::Engine::Delegate| -void Shell::OnEngineUpdateSemantics(const Engine& engine, - blink::SemanticsNodeUpdates update) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); +void Shell::Init(fxl::CommandLine command_line, + const std::string& bundle_path) { +#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE + bool trace_skia = command_line.HasOption(FlagForSwitch(Switch::TraceSkia)); + InitSkiaEventTracer(trace_skia); +#endif - task_runners_.GetPlatformTaskRunner()->PostTask( - [view = platform_view_->GetWeakPtr(), update = std::move(update)] { - if (view) { - view->UpdateSemantics(std::move(update)); - } - }); + FXL_DCHECK(!g_shell); + g_shell = new Shell(std::move(command_line)); + blink::Threads::UI()->PostTask( + [bundle_path]() { Engine::Init(bundle_path); }); } -// |shell::Engine::Delegate| -void Shell::OnEngineHandlePlatformMessage( - const Engine& engine, - fxl::RefPtr message) { - FXL_DCHECK(is_setup_); - FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - - task_runners_.GetPlatformTaskRunner()->PostTask( - [view = platform_view_->GetWeakPtr(), message = std::move(message)]() { - if (view) { - view->HandlePlatformMessage(std::move(message)); - } - }); +Shell& Shell::Shared() { + FXL_DCHECK(g_shell); + return *g_shell; } -// |blink::ServiceProtocol::Handler| -fxl::RefPtr Shell::GetServiceProtocolHandlerTaskRunner( - fxl::StringView method) const { - FXL_DCHECK(is_setup_); - auto found = service_protocol_handlers_.find(method.ToString()); - if (found != service_protocol_handlers_.end()) { - return found->second.first; - } - return task_runners_.GetUITaskRunner(); +const fxl::CommandLine& Shell::GetCommandLine() const { + return command_line_; } -// |blink::ServiceProtocol::Handler| -bool Shell::HandleServiceProtocolMessage( - fxl::StringView method, // one if the extension names specified above. - const ServiceProtocolMap& params, - rapidjson::Document& response) { - auto found = service_protocol_handlers_.find(method.ToString()); - if (found != service_protocol_handlers_.end()) { - return found->second.second(params, response); - } - return false; +void Shell::InitGpuThread() { + gpu_thread_checker_.reset(new fxl::ThreadChecker()); } -// |blink::ServiceProtocol::Handler| -blink::ServiceProtocol::Handler::Description -Shell::GetServiceProtocolDescription() const { - return { - engine_->GetUIIsolateMainPort(), - engine_->GetUIIsolateName(), - }; +void Shell::InitUIThread() { + ui_thread_checker_.reset(new fxl::ThreadChecker()); } -static void ServiceProtocolParameterError(rapidjson::Document& response, - std::string parameter_name) { - auto& allocator = response.GetAllocator(); - response.SetObject(); - const int64_t kInvalidParams = -32602; - response.AddMember("code", kInvalidParams, allocator); - response.AddMember("message", "Invalid params", allocator); - { - rapidjson::Value details(rapidjson::kObjectType); - details.AddMember("details", parameter_name, allocator); - response.AddMember("data", details, allocator); +void Shell::AddPlatformView(PlatformView* platform_view) { + if (platform_view == nullptr) { + return; } + std::lock_guard lock(platform_views_mutex_); + platform_views_.insert(platform_view); } -// Service protocol handler -bool Shell::OnServiceProtocolScreenshot( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response) { - FXL_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread()); - auto screenshot = rasterizer_->ScreenshotLastLayerTree( - Rasterizer::ScreenshotType::CompressedImage, true); - if (screenshot.data) { - response.SetObject(); - auto& allocator = response.GetAllocator(); - response.AddMember("type", "Screenshot", allocator); - rapidjson::Value image; - image.SetString(static_cast(screenshot.data->data()), - screenshot.data->size(), allocator); - response.AddMember("screenshot", image, allocator); - return true; +void Shell::RemovePlatformView(PlatformView* platform_view) { + if (platform_view == nullptr) { + return; } - ServiceProtocolParameterError(response, - "Could not capture image screenshot."); - return false; + std::lock_guard lock(platform_views_mutex_); + platform_views_.erase(platform_view); } -// Service protocol handler -bool Shell::OnServiceProtocolScreenshotSKP( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response) { - FXL_DCHECK(task_runners_.GetGPUTaskRunner()->RunsTasksOnCurrentThread()); - auto screenshot = rasterizer_->ScreenshotLastLayerTree( - Rasterizer::ScreenshotType::SkiaPicture, true); - if (screenshot.data) { - response.SetObject(); - auto& allocator = response.GetAllocator(); - response.AddMember("type", "ScreenshotSkp", allocator); - rapidjson::Value skp; - skp.SetString(static_cast(screenshot.data->data()), - screenshot.data->size(), allocator); - response.AddMember("skp", skp, allocator); - return true; +void Shell::IteratePlatformViews( + std::function iterator) const { + if (iterator == nullptr) { + return; } - ServiceProtocolParameterError(response, "Could not capture SKP screenshot."); - return false; -} - -// Service protocol handler -bool Shell::OnServiceProtocolRunInView( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response) { - FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - - if (params.count("mainScript") == 0) { - ServiceProtocolParameterError(response, - "'mainScript' parameter is missing."); - return false; - } - - if (params.count("packagesFile") == 0) { - ServiceProtocolParameterError(response, - "'packagesFile' parameter is missing."); - return false; - } - - if (params.count("assetDirectory") == 0) { - ServiceProtocolParameterError(response, - "'assetDirectory' parameter is missing."); - return false; - } - - RunConfiguration configuration(IsolateConfiguration::CreateForSource( - params.at("mainScript").ToString(), - params.at("packagesFile").ToString())); - - configuration.AddAssetResolver(std::make_unique( - fml::OpenFile(params.at("assetDirectory").ToString().c_str(), - fml::OpenPermission::kRead, true))); - - auto& allocator = response.GetAllocator(); - response.SetObject(); - if (engine_->Restart(std::move(configuration))) { - response.AddMember("type", "Success", allocator); - auto new_description = GetServiceProtocolDescription(); - rapidjson::Value view(rapidjson::kObjectType); - new_description.Write(this, view, allocator); - response.AddMember("view", view, allocator); - return true; - } else { - FXL_DLOG(ERROR) << "Could not run configuration in engine."; - response.AddMember("type", "Failure", allocator); - return false; + std::lock_guard lock(platform_views_mutex_); + for (PlatformView* view : platform_views_) { + if (!iterator(view)) { + return; + } } - - FXL_DCHECK(false); - return false; } -// Service protocol handler -bool Shell::OnServiceProtocolFlushUIThreadTasks( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response) { - FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - // This API should not be invoked by production code. - // It can potentially starve the service isolate if the main isolate pauses - // at a breakpoint or is in an infinite loop. - // - // It should be invoked from the VM Service and and blocks it until UI thread - // tasks are processed. - response.SetObject(); - response.AddMember("type", "Success", response.GetAllocator()); - return true; +void Shell::RunInPlatformView(uintptr_t view_id, + const char* main_script, + const char* packages_file, + const char* asset_directory, + bool* view_existed, + int64_t* dart_isolate_id, + std::string* isolate_name) { + fxl::AutoResetWaitableEvent latch; + FXL_DCHECK(view_id != 0); + FXL_DCHECK(main_script); + FXL_DCHECK(packages_file); + FXL_DCHECK(asset_directory); + FXL_DCHECK(view_existed); + + blink::Threads::UI()->PostTask([this, view_id, main_script, packages_file, + asset_directory, view_existed, + dart_isolate_id, isolate_name, &latch]() { + RunInPlatformViewUIThread(view_id, main_script, packages_file, + asset_directory, view_existed, dart_isolate_id, + isolate_name, &latch); + }); + latch.Wait(); } -// Service protocol handler -bool Shell::OnServiceProtocolSetAssetBundlePath( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response) { - FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - - if (params.count("assetDirectory") == 0) { - ServiceProtocolParameterError(response, - "'assetDirectory' parameter is missing."); - return false; - } - - auto& allocator = response.GetAllocator(); - response.SetObject(); - - auto asset_manager = fxl::MakeRefCounted(); - - asset_manager->PushFront(std::make_unique( - fml::OpenFile(params.at("assetDirectory").ToString().c_str(), - fml::OpenPermission::kRead, true))); - - if (engine_->UpdateAssetManager(std::move(asset_manager))) { - response.AddMember("type", "Success", allocator); - auto new_description = GetServiceProtocolDescription(); - rapidjson::Value view(rapidjson::kObjectType); - new_description.Write(this, view, allocator); - response.AddMember("view", view, allocator); - return true; - } else { - FXL_DLOG(ERROR) << "Could not update asset directory."; - response.AddMember("type", "Failure", allocator); - return false; - } +void Shell::RunInPlatformViewUIThread(uintptr_t view_id, + const std::string& main, + const std::string& packages, + const std::string& assets_directory, + bool* view_existed, + int64_t* dart_isolate_id, + std::string* isolate_name, + fxl::AutoResetWaitableEvent* latch) { + FXL_DCHECK(ui_thread_checker_ && + ui_thread_checker_->IsCreationThreadCurrent()); + + *view_existed = false; + + IteratePlatformViews( + [view_id, // argument +#if !defined(OS_WIN) + // Using std::move on const references inside lambda capture is + // not supported on Windows for some reason. + assets_directory = std::move(assets_directory), // argument + main = std::move(main), // argument + packages = std::move(packages), // argument +#else + assets_directory, // argument + main, // argument + packages, // argument +#endif + &view_existed, // out + &dart_isolate_id, // out + &isolate_name // out + ](PlatformView* view) -> bool { + if (reinterpret_cast(view) != view_id) { + // Keep looking. + return true; + } + *view_existed = true; + view->RunFromSource(assets_directory, main, packages); + *dart_isolate_id = view->engine().GetUIIsolateMainPort(); + *isolate_name = view->engine().GetUIIsolateName(); + // We found the requested view. Stop iterating over platform views. + return false; + }); - FXL_DCHECK(false); - return false; + latch->Signal(); } -Rasterizer::Screenshot Shell::Screenshot( - Rasterizer::ScreenshotType screenshot_type, - bool base64_encode) { - TRACE_EVENT0("flutter", "Shell::Screenshot"); +void Shell::SetAssetBundlePathInPlatformView(uintptr_t view_id, + const char* asset_directory, + bool* view_existed, + int64_t* dart_isolate_id, + std::string* isolate_name) { fxl::AutoResetWaitableEvent latch; - Rasterizer::Screenshot screenshot; - fml::TaskRunner::RunNowOrPostTask( - task_runners_.GetGPUTaskRunner(), [&latch, // - rasterizer = GetRasterizer(), // - &screenshot, // - screenshot_type, // - base64_encode // - ]() { - if (rasterizer) { - screenshot = rasterizer->ScreenshotLastLayerTree(screenshot_type, - base64_encode); + FXL_DCHECK(view_id != 0); + FXL_DCHECK(asset_directory); + FXL_DCHECK(view_existed); + + blink::Threads::UI()->PostTask([this, view_id, asset_directory, view_existed, + dart_isolate_id, isolate_name, &latch]() { + SetAssetBundlePathInPlatformViewUIThread(view_id, asset_directory, + view_existed, dart_isolate_id, + isolate_name, &latch); + }); + latch.Wait(); +} + +void Shell::SetAssetBundlePathInPlatformViewUIThread( + uintptr_t view_id, + const std::string& assets_directory, + bool* view_existed, + int64_t* dart_isolate_id, + std::string* isolate_name, + fxl::AutoResetWaitableEvent* latch) { + FXL_DCHECK(ui_thread_checker_ && + ui_thread_checker_->IsCreationThreadCurrent()); + + *view_existed = false; + + IteratePlatformViews( + [view_id, // argument +#if !defined(OS_WIN) + // Using std::move on const references inside lambda capture is + // not supported on Windows for some reason. + // TODO(https://github.com/flutter/flutter/issues/13908): + // Investigate the root cause of the difference. + assets_directory = std::move(assets_directory), // argument +#else + assets_directory, // argument +#endif + &view_existed, // out + &dart_isolate_id, // out + &isolate_name // out + ](PlatformView* view) -> bool { + if (reinterpret_cast(view) != view_id) { + // Keep looking. + return true; } - latch.Signal(); + *view_existed = true; + view->SetAssetBundlePath(assets_directory); + *dart_isolate_id = view->engine().GetUIIsolateMainPort(); + *isolate_name = view->engine().GetUIIsolateName(); + // We found the requested view. Stop iterating over + // platform views. + return false; }); - latch.Wait(); - return screenshot; + + latch->Signal(); } } // namespace shell diff --git a/shell/common/shell.h b/shell/common/shell.h index 02a642b0ba40f..92c315dcf2aa7 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -5,214 +5,96 @@ #ifndef SHELL_COMMON_SHELL_H_ #define SHELL_COMMON_SHELL_H_ -#include -#include - -#include "flutter/common/settings.h" -#include "flutter/common/task_runners.h" -#include "flutter/flow/texture.h" -#include "flutter/fml/memory/thread_checker.h" -#include "flutter/fml/memory/weak_ptr.h" +#include +#include + #include "flutter/fml/thread.h" -#include "flutter/lib/ui/semantics/semantics_node.h" -#include "flutter/lib/ui/window/platform_message.h" -#include "flutter/runtime/service_protocol.h" -#include "flutter/shell/common/animator.h" -#include "flutter/shell/common/engine.h" -#include "flutter/shell/common/io_manager.h" -#include "flutter/shell/common/platform_view.h" -#include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/surface.h" +#include "flutter/shell/common/tracing_controller.h" +#include "lib/fxl/command_line.h" #include "lib/fxl/functional/closure.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_ptr.h" #include "lib/fxl/memory/weak_ptr.h" -#include "lib/fxl/strings/string_view.h" -#include "lib/fxl/synchronization/thread_annotations.h" #include "lib/fxl/synchronization/thread_checker.h" #include "lib/fxl/synchronization/waitable_event.h" +#include "lib/fxl/tasks/task_runner.h" namespace shell { -class Shell final : public PlatformView::Delegate, - public Animator::Delegate, - public Engine::Delegate, - public blink::ServiceProtocol::Handler { - public: - template - using CreateCallback = std::function(Shell&)>; - static std::unique_ptr Create( - blink::TaskRunners task_runners, - blink::Settings settings, - CreateCallback on_create_platform_view, - CreateCallback on_create_rasterizer); +class PlatformView; +class Shell { + public: ~Shell(); - const blink::Settings& GetSettings() const; + static void InitStandalone(fxl::CommandLine command_line, + std::string icu_data_path = "", + std::string application_library_path = "", + std::string bundle_path = ""); - const blink::TaskRunners& GetTaskRunners() const; + static Shell& Shared(); - fml::WeakPtr GetRasterizer(); + const fxl::CommandLine& GetCommandLine() const; - fml::WeakPtr GetEngine(); + void AddPlatformView(PlatformView* platform_view); - fml::WeakPtr GetPlatformView(); + void RemovePlatformView(PlatformView* platform_view); - const blink::DartVM& GetDartVM() const; + void IteratePlatformViews( + std::function iterator) const; - bool IsSetup() const; + // Attempt to run a script inside a flutter view indicated by |view_id|. + // Will set |view_existed| to true if the view was found and false otherwise. + void RunInPlatformView(uintptr_t view_id, + const char* main_script, + const char* packages_file, + const char* asset_directory, + bool* view_existed, + int64_t* dart_isolate_id, + std::string* isolate_name); - Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type, - bool base64_encode); + void SetAssetBundlePathInPlatformView(uintptr_t view_id, + const char* asset_directory, + bool* view_existed, + int64_t* dart_isolate_id, + std::string* isolate_name); private: - using ServiceProtocolHandler = std::function; - - const blink::TaskRunners task_runners_; - const blink::Settings settings_; - fxl::RefPtr vm_; - std::unique_ptr platform_view_; // on platform task runner - std::unique_ptr engine_; // on UI task runner - std::unique_ptr rasterizer_; // on GPU task runner - std::unique_ptr io_manager_; // on IO task runner - - std::unordered_map, - ServiceProtocolHandler> // task-runner/function - // pair - > - service_protocol_handlers_; - bool is_setup_ = false; - - Shell(blink::TaskRunners task_runners, blink::Settings settings); - - static std::unique_ptr CreateShellOnPlatformThread( - blink::TaskRunners task_runners, - blink::Settings settings, - Shell::CreateCallback on_create_platform_view, - Shell::CreateCallback on_create_rasterizer); - - bool Setup(std::unique_ptr platform_view, - std::unique_ptr engine, - std::unique_ptr rasterizer, - std::unique_ptr io_manager); - - // |shell::PlatformView::Delegate| - void OnPlatformViewCreated(const PlatformView& view, - std::unique_ptr surface) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewDestroyed(const PlatformView& view) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewSetViewportMetrics( - const PlatformView& view, - const blink::ViewportMetrics& metrics) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewDispatchPlatformMessage( - const PlatformView& view, - fxl::RefPtr message) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewDispatchPointerDataPacket( - const PlatformView& view, - std::unique_ptr packet) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewDispatchSemanticsAction( - const PlatformView& view, - int32_t id, - blink::SemanticsAction action, - std::vector args) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewSetSemanticsEnabled(const PlatformView& view, - bool enabled) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewRegisterTexture( - const PlatformView& view, - std::shared_ptr texture) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewUnregisterTexture(const PlatformView& view, - int64_t texture_id) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewMarkTextureFrameAvailable(const PlatformView& view, - int64_t texture_id) override; - - // |shell::PlatformView::Delegate| - void OnPlatformViewSetNextFrameCallback(const PlatformView& view, - fxl::Closure closure) override; - - // |shell::Animator::Delegate| - void OnAnimatorBeginFrame(const Animator& animator, - fxl::TimePoint frame_time) override; - - // |shell::Animator::Delegate| - void OnAnimatorNotifyIdle(const Animator& animator, - int64_t deadline) override; - - // |shell::Animator::Delegate| - void OnAnimatorDraw( - const Animator& animator, - fxl::RefPtr> pipeline) override; - - // |shell::Animator::Delegate| - void OnAnimatorDrawLastLayerTree(const Animator& animator) override; - - // |shell::Engine::Delegate| - void OnEngineUpdateSemantics(const Engine& engine, - blink::SemanticsNodeUpdates update) override; - - // |shell::Engine::Delegate| - void OnEngineHandlePlatformMessage( - const Engine& engine, - fxl::RefPtr message) override; - - // |blink::ServiceProtocol::Handler| - fxl::RefPtr GetServiceProtocolHandlerTaskRunner( - fxl::StringView method) const override; - - // |blink::ServiceProtocol::Handler| - bool HandleServiceProtocolMessage( - fxl::StringView method, // one if the extension names specified above. - const ServiceProtocolMap& params, - rapidjson::Document& response) override; - - // |blink::ServiceProtocol::Handler| - blink::ServiceProtocol::Handler::Description GetServiceProtocolDescription() - const override; - - // Service protocol handler - bool OnServiceProtocolScreenshot( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response); - - // Service protocol handler - bool OnServiceProtocolScreenshotSKP( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response); - - // Service protocol handler - bool OnServiceProtocolRunInView( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response); - - // Service protocol handler - bool OnServiceProtocolFlushUIThreadTasks( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response); - - // Service protocol handler - bool OnServiceProtocolSetAssetBundlePath( - const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, - rapidjson::Document& response); + fxl::CommandLine command_line_; + std::unique_ptr gpu_thread_; + std::unique_ptr ui_thread_; + std::unique_ptr io_thread_; + std::unique_ptr gpu_thread_checker_; + std::unique_ptr ui_thread_checker_; + TracingController tracing_controller_; + mutable std::mutex platform_views_mutex_; + std::unordered_set platform_views_; + + static void Init(fxl::CommandLine command_line, + const std::string& bundle_path); + + Shell(fxl::CommandLine command_line); + + void InitGpuThread(); + + void InitUIThread(); + + void RunInPlatformViewUIThread(uintptr_t view_id, + const std::string& main, + const std::string& packages, + const std::string& assets_directory, + bool* view_existed, + int64_t* dart_isolate_id, + std::string* isolate_name, + fxl::AutoResetWaitableEvent* latch); + + void SetAssetBundlePathInPlatformViewUIThread( + uintptr_t view_id, + const std::string& main, + bool* view_existed, + int64_t* dart_isolate_id, + std::string* isolate_name, + fxl::AutoResetWaitableEvent* latch); FXL_DISALLOW_COPY_AND_ASSIGN(Shell); }; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc deleted file mode 100644 index 67689341a1586..0000000000000 --- a/shell/common/shell_unittests.cc +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright 2017 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. - -#define FML_USED_ON_EMBEDDER - -#include -#include -#include - -#include "flutter/fml/message_loop.h" -#include "flutter/shell/common/platform_view.h" -#include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/shell.h" -#include "flutter/shell/common/thread_host.h" -#include "gtest/gtest.h" -#include "lib/fxl/synchronization/waitable_event.h" - -#define CURRENT_TEST_NAME \ - std::string { \ - ::testing::UnitTest::GetInstance()->current_test_info()->name() \ - } - -namespace shell { - -TEST(ShellTest, InitializeWithInvalidThreads) { - blink::Settings settings = {}; - settings.task_observer_add = [](intptr_t, fxl::Closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - settings.using_blink = false; - blink::TaskRunners task_runners("test", nullptr, nullptr, nullptr, nullptr); - auto shell = Shell::Create( - std::move(task_runners), settings, - [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); - }, - [](Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }); - ASSERT_FALSE(shell); -} - -TEST(ShellTest, InitializeWithDifferentThreads) { - blink::Settings settings = {}; - settings.task_observer_add = [](intptr_t, fxl::Closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - settings.using_blink = false; - ThreadHost thread_host("io.flutter.test." + CURRENT_TEST_NAME + ".", - ThreadHost::Type::Platform | ThreadHost::Type::GPU | - ThreadHost::Type::IO | ThreadHost::Type::UI); - blink::TaskRunners task_runners("test", - thread_host.platform_thread->GetTaskRunner(), - thread_host.gpu_thread->GetTaskRunner(), - thread_host.ui_thread->GetTaskRunner(), - thread_host.io_thread->GetTaskRunner()); - auto shell = Shell::Create( - std::move(task_runners), settings, - [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); - }, - [](Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }); - ASSERT_TRUE(shell); -} - -TEST(ShellTest, InitializeWithSingleThread) { - blink::Settings settings = {}; - settings.task_observer_add = [](intptr_t, fxl::Closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - settings.using_blink = false; - ThreadHost thread_host("io.flutter.test." + CURRENT_TEST_NAME + ".", - ThreadHost::Type::Platform); - auto task_runner = thread_host.platform_thread->GetTaskRunner(); - blink::TaskRunners task_runners("test", task_runner, task_runner, task_runner, - task_runner); - auto shell = Shell::Create( - std::move(task_runners), settings, - [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); - }, - [](Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }); - ASSERT_TRUE(shell); -} - -TEST(ShellTest, InitializeWithSingleThreadWhichIsTheCallingThread) { - blink::Settings settings = {}; - settings.task_observer_add = [](intptr_t, fxl::Closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - settings.using_blink = false; - fml::MessageLoop::EnsureInitializedForCurrentThread(); - auto task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); - blink::TaskRunners task_runners("test", task_runner, task_runner, task_runner, - task_runner); - auto shell = Shell::Create( - std::move(task_runners), settings, - [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); - }, - [](Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }); - ASSERT_TRUE(shell); -} - -TEST(ShellTest, InitializeWithMultipleThreadButCallingThreadAsPlatformThread) { - blink::Settings settings = {}; - settings.task_observer_add = [](intptr_t, fxl::Closure) {}; - settings.task_observer_remove = [](intptr_t) {}; - settings.using_blink = false; - ThreadHost thread_host( - "io.flutter.test." + CURRENT_TEST_NAME + ".", - ThreadHost::Type::GPU | ThreadHost::Type::IO | ThreadHost::Type::UI); - fml::MessageLoop::EnsureInitializedForCurrentThread(); - blink::TaskRunners task_runners( - "test", fml::MessageLoop::GetCurrent().GetTaskRunner(), - thread_host.gpu_thread->GetTaskRunner(), - thread_host.ui_thread->GetTaskRunner(), - thread_host.io_thread->GetTaskRunner()); - auto shell = Shell::Create( - std::move(task_runners), settings, - [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); - }, - [](Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }); - ASSERT_TRUE(shell); -} - -} // namespace shell diff --git a/shell/common/surface.cc b/shell/common/surface.cc index 228647e8b3512..01d288a5e5085 100644 --- a/shell/common/surface.cc +++ b/shell/common/surface.cc @@ -3,7 +3,6 @@ // found in the LICENSE file. #include "flutter/shell/common/surface.h" - #include "lib/fxl/logging.h" #include "third_party/skia/include/core/SkColorSpaceXformCanvas.h" #include "third_party/skia/include/core/SkSurface.h" @@ -60,22 +59,27 @@ bool SurfaceFrame::PerformSubmit() { return false; } -Surface::Surface() : Surface(std::make_unique()) {} +Surface::Surface() : scale_(1.0) {} + +Surface::~Surface() = default; -Surface::Surface(std::unique_ptr compositor_context) - : compositor_context_(std::move(compositor_context)) { - FXL_DCHECK(compositor_context_); - // TODO: Get rid of these explicit calls and move the logic to the c/dtors of - // the compositor context. - compositor_context_->OnGrContextCreated(); +bool Surface::SupportsScaling() const { + return false; } -Surface::~Surface() { - compositor_context_->OnGrContextDestroyed(); +double Surface::GetScale() const { + return scale_; } -flow::CompositorContext& Surface::GetCompositorContext() { - return *compositor_context_; +void Surface::SetScale(double scale) { + static constexpr double kMaxScale = 1.0; + static constexpr double kMinScale = 0.25; + if (scale > kMaxScale) { + scale = kMaxScale; + } else if (scale < kMinScale) { + scale = kMinScale; + } + scale_ = scale; } } // namespace shell diff --git a/shell/common/surface.h b/shell/common/surface.h index 6133a7d519fff..906480237f416 100644 --- a/shell/common/surface.h +++ b/shell/common/surface.h @@ -7,7 +7,7 @@ #include -#include "flutter/flow/compositor_context.h" +#include "lib/fxl/compiler_specific.h" #include "lib/fxl/macros.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -45,8 +45,6 @@ class Surface { public: Surface(); - Surface(std::unique_ptr compositor_context); - virtual ~Surface(); virtual bool IsValid() = 0; @@ -55,12 +53,14 @@ class Surface { virtual GrContext* GetContext() = 0; - flow::CompositorContext& GetCompositorContext(); + virtual bool SupportsScaling() const; - private: - std::unique_ptr compositor_context_; + double GetScale() const; - FXL_DISALLOW_COPY_AND_ASSIGN(Surface); + void SetScale(double scale); + + private: + double scale_; }; } // namespace shell diff --git a/shell/common/switches.cc b/shell/common/switches.cc index 82da6ee180af8..c1c82ff166ac1 100644 --- a/shell/common/switches.cc +++ b/shell/common/switches.cc @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -91,125 +90,4 @@ const fxl::StringView FlagForSwitch(Switch swtch) { return fxl::StringView(); } -template -static bool GetSwitchValue(const fxl::CommandLine& command_line, - shell::Switch sw, - T* result) { - std::string switch_string; - - if (!command_line.GetOptionValue(shell::FlagForSwitch(sw), &switch_string)) { - return false; - } - - std::stringstream stream(switch_string); - T value = 0; - if (stream >> value) { - *result = value; - return true; - } - - return false; -} - -blink::Settings SettingsFromCommandLine(const fxl::CommandLine& command_line) { - blink::Settings settings = {}; - - // Enable Observatory - settings.enable_observatory = - !command_line.HasOption(FlagForSwitch(Switch::DisableObservatory)); - - // Set Observatory Port - if (command_line.HasOption(FlagForSwitch(Switch::DeviceObservatoryPort))) { - if (!GetSwitchValue(command_line, Switch::DeviceObservatoryPort, - &settings.observatory_port)) { - FXL_LOG(INFO) - << "Observatory port specified was malformed. Will default to " - << settings.observatory_port; - } - } - - // Checked mode overrides. - settings.dart_non_checked_mode = - command_line.HasOption(FlagForSwitch(Switch::DartNonCheckedMode)); - - settings.ipv6 = command_line.HasOption(FlagForSwitch(Switch::IPv6)); - - settings.start_paused = - command_line.HasOption(FlagForSwitch(Switch::StartPaused)); - - settings.enable_dart_profiling = - command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling)); - - settings.enable_software_rendering = - command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering)); - - settings.using_blink = - command_line.HasOption(FlagForSwitch(Switch::EnableBlink)); - - settings.endless_trace_buffer = - command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer)); - - settings.trace_startup = - command_line.HasOption(FlagForSwitch(Switch::TraceStartup)); - - settings.skia_deterministic_rendering_on_cpu = - command_line.HasOption(FlagForSwitch(Switch::SkiaDeterministicRendering)); - - command_line.GetOptionValue(FlagForSwitch(Switch::FLX), &settings.flx_path); - - command_line.GetOptionValue(FlagForSwitch(Switch::FlutterAssetsDir), - &settings.assets_path); - - command_line.GetOptionValue(FlagForSwitch(Switch::Snapshot), - &settings.script_snapshot_path); - - command_line.GetOptionValue(FlagForSwitch(Switch::MainDartFile), - &settings.main_dart_file_path); - - command_line.GetOptionValue(FlagForSwitch(Switch::Packages), - &settings.packages_file_path); - - command_line.GetOptionValue(FlagForSwitch(Switch::AotSnapshotPath), - &settings.aot_snapshot_path); - - command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotData), - &settings.aot_vm_snapshot_data_filename); - - command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotInstructions), - &settings.aot_vm_snapshot_instr_filename); - - command_line.GetOptionValue(FlagForSwitch(Switch::AotIsolateSnapshotData), - &settings.aot_isolate_snapshot_data_filename); - - command_line.GetOptionValue( - FlagForSwitch(Switch::AotIsolateSnapshotInstructions), - &settings.aot_isolate_snapshot_instr_filename); - - command_line.GetOptionValue(FlagForSwitch(Switch::CacheDirPath), - &settings.temp_directory_path); - - command_line.GetOptionValue(FlagForSwitch(Switch::ICUDataFilePath), - &settings.icu_data_path); - - settings.use_test_fonts = - command_line.HasOption(FlagForSwitch(Switch::UseTestFonts)); - - command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag); - std::string all_dart_flags; - if (command_line.GetOptionValue(FlagForSwitch(Switch::DartFlags), - &all_dart_flags)) { - std::stringstream stream(all_dart_flags); - std::istream_iterator end; - for (std::istream_iterator it(stream); it != end; ++it) - settings.dart_flags.push_back(*it); - } - -#if FLUTTER_RUNTIME_MODE != FLUTTER_RUNTIME_MODE_RELEASE - settings.trace_skia = - command_line.HasOption(FlagForSwitch(Switch::TraceSkia)); -#endif - - return settings; -} - } // namespace shell diff --git a/shell/common/switches.h b/shell/common/switches.h index 6b67b1f6a1567..91778a78e92cc 100644 --- a/shell/common/switches.h +++ b/shell/common/switches.h @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/common/settings.h" -#include "lib/fxl/command_line.h" #include "lib/fxl/strings/string_view.h" #ifndef SHELL_COMMON_SWITCHES_H_ @@ -25,29 +23,12 @@ namespace shell { DEF_SWITCHES_START DEF_SWITCH(AotSharedLibraryPath, "aot-shared-library-path", "Path to the *.so.") -DEF_SWITCH(AotSnapshotPath, - "aot-snapshot-path", - "Path to the directory containing the four files specified by " - "AotVmSnapshotData, AotVmSnapshotInstructions, " - "AotVmSnapshotInstructions and AotIsolateSnapshotInstructions.") -DEF_SWITCH(AotVmSnapshotData, - "vm-snapshot-data", - "The VM snapshot data that will be memory mapped as read-only. " - "AotSnapshotPath must be present.") -DEF_SWITCH(AotVmSnapshotInstructions, - "vm-snapshot-instr", - "The VM instructions snapshot that will be memory mapped as read " - "and executable. AotSnapshotPath must be present.") -DEF_SWITCH(AotIsolateSnapshotData, - "isolate-snapshot-data", - "The isolate snapshot data that will be memory mapped as read-only. " - "AotSnapshotPath must be present.") -DEF_SWITCH(AotIsolateSnapshotInstructions, - "isolate-snapshot-instr", - "The isolate instructions snapshot that will be memory mapped as " - "read and executable. AotSnapshotPath must be present.") +DEF_SWITCH(AotSnapshotPath, "aot-snapshot-path", "Path to the AOT snapshot.") +DEF_SWITCH(AotVmSnapshotData, "vm-snapshot-data", "") +DEF_SWITCH(AotVmSnapshotInstructions, "vm-snapshot-instr", "") +DEF_SWITCH(AotIsolateSnapshotData, "isolate-snapshot-data", "") +DEF_SWITCH(AotIsolateSnapshotInstructions, "isolate-snapshot-instr", "") DEF_SWITCH(CacheDirPath, "cache-dir-path", "Path to the cache directory.") -DEF_SWITCH(ICUDataFilePath, "icu-data-file-path", "Path to the ICU data file.") DEF_SWITCH(DartFlags, "dart-flags", "Flags passed directly to the Dart VM without being interpreted " @@ -92,6 +73,10 @@ DEF_SWITCH(FlutterAssetsDir, DEF_SWITCH(Help, "help", "Display this help text.") DEF_SWITCH(LogTag, "log-tag", "Tag associated with log messages.") DEF_SWITCH(MainDartFile, "dart-main", "The path to the main Dart file.") +DEF_SWITCH(NonInteractive, + "non-interactive", + "Make the shell non-interactive. By default, the shell attempts " + "to setup a window and create an OpenGL context.") DEF_SWITCH(Packages, "packages", "Specify the path to the packages.") DEF_SWITCH(Snapshot, "snapshot-blob", "Specify the path to the snapshot blob") DEF_SWITCH(StartPaused, @@ -128,9 +113,7 @@ DEF_SWITCHES_END void PrintUsage(const std::string& executable_name); -const fxl::StringView FlagForSwitch(Switch swtch); - -blink::Settings SettingsFromCommandLine(const fxl::CommandLine& command_line); +const fxl::StringView FlagForSwitch(Switch sw); } // namespace shell diff --git a/shell/common/thread_host.cc b/shell/common/thread_host.cc deleted file mode 100644 index f35594829d5d9..0000000000000 --- a/shell/common/thread_host.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/shell/common/thread_host.h" - -namespace shell { - -ThreadHost::ThreadHost() = default; - -ThreadHost::ThreadHost(std::string name_prefix, uint64_t mask) { - if (mask & ThreadHost::Type::Platform) { - platform_thread = std::make_unique(name_prefix + ".platform"); - } - - if (mask & ThreadHost::Type::UI) { - ui_thread = std::make_unique(name_prefix + ".ui"); - } - - if (mask & ThreadHost::Type::GPU) { - gpu_thread = std::make_unique(name_prefix + ".gpu"); - } - - if (mask & ThreadHost::Type::IO) { - io_thread = std::make_unique(name_prefix + ".io"); - } -} - -ThreadHost::~ThreadHost() = default; - -void ThreadHost::Reset() { - platform_thread.reset(); - ui_thread.reset(); - gpu_thread.reset(); - io_thread.reset(); -} - -} // namespace shell diff --git a/shell/common/thread_host.h b/shell/common/thread_host.h deleted file mode 100644 index a688aa6a06a85..0000000000000 --- a/shell/common/thread_host.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017 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_COMMON_THREAD_HOST_H_ -#define FLUTTER_SHELL_COMMON_THREAD_HOST_H_ - -#include - -#include "flutter/fml/thread.h" -#include "lib/fxl/macros.h" - -namespace shell { - -struct ThreadHost { - enum Type { - Platform = 1 << 0, - UI = 1 << 1, - GPU = 1 << 2, - IO = 1 << 3, - }; - - std::unique_ptr platform_thread; - std::unique_ptr ui_thread; - std::unique_ptr gpu_thread; - std::unique_ptr io_thread; - - ThreadHost(); - - ThreadHost(ThreadHost&&) = default; - - ThreadHost& operator=(ThreadHost&&) = default; - - ThreadHost(std::string name_prefix, uint64_t type_mask); - - ~ThreadHost(); - - void Reset(); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_COMMON_THREAD_HOST_H_ diff --git a/shell/common/tracing_controller.cc b/shell/common/tracing_controller.cc new file mode 100644 index 0000000000000..6fa8d9d5ee87f --- /dev/null +++ b/shell/common/tracing_controller.cc @@ -0,0 +1,51 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/common/tracing_controller.h" + +#include + +#include "flutter/common/threads.h" +#include "flutter/fml/trace_event.h" +#include "flutter/runtime/dart_init.h" +#include "flutter/shell/common/shell.h" +#include "lib/fxl/logging.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +namespace shell { + +TracingController::TracingController() : tracing_active_(false) { + blink::SetEmbedderTracingCallbacks( + std::unique_ptr( + new blink::EmbedderTracingCallbacks([this]() { StartTracing(); }, + [this]() { StopTracing(); }))); +} + +TracingController::~TracingController() { + blink::SetEmbedderTracingCallbacks(nullptr); +} + +static void AddTraceMetadata() { + blink::Threads::Gpu()->PostTask([]() { Dart_SetThreadName("gpu_thread"); }); + blink::Threads::UI()->PostTask([]() { Dart_SetThreadName("ui_thread"); }); + blink::Threads::IO()->PostTask([]() { Dart_SetThreadName("io_thread"); }); + blink::Threads::Platform()->PostTask( + []() { Dart_SetThreadName("platform_thread"); }); +} + +void TracingController::StartTracing() { + if (tracing_active_) + return; + tracing_active_ = true; + AddTraceMetadata(); +} + +void TracingController::StopTracing() { + if (!tracing_active_) { + return; + } + tracing_active_ = false; +} + +} // namespace shell diff --git a/shell/common/tracing_controller.h b/shell/common/tracing_controller.h new file mode 100644 index 0000000000000..3f9e6f03ab14c --- /dev/null +++ b/shell/common/tracing_controller.h @@ -0,0 +1,34 @@ +// Copyright 2015 The Chromium 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 SHELL_COMMON_TRACING_CONTROLLER_H_ +#define SHELL_COMMON_TRACING_CONTROLLER_H_ + +#include + +#include "lib/fxl/macros.h" + +namespace shell { + +class TracingController { + public: + TracingController(); + + ~TracingController(); + + void StartTracing(); + + void StopTracing(); + + bool tracing_active() const { return tracing_active_; } + + private: + bool tracing_active_; + + FXL_DISALLOW_COPY_AND_ASSIGN(TracingController); +}; + +} // namespace shell + +#endif // SHELL_COMMON_TRACING_CONTROLLER_H_ diff --git a/shell/common/vsync_waiter.cc b/shell/common/vsync_waiter.cc index ba2f21c389c11..5acc235b1f68d 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -4,45 +4,8 @@ #include "flutter/shell/common/vsync_waiter.h" -#include "flutter/fml/task_runner.h" -#include "flutter/fml/trace_event.h" - namespace shell { -VsyncWaiter::VsyncWaiter(blink::TaskRunners task_runners) - : task_runners_(std::move(task_runners)) {} - VsyncWaiter::~VsyncWaiter() = default; -void VsyncWaiter::AsyncWaitForVsync(Callback callback) { - { - std::lock_guard lock(callback_mutex_); - callback_ = std::move(callback); - } - AwaitVSync(); -} - -void VsyncWaiter::FireCallback(fxl::TimePoint frame_start_time, - fxl::TimePoint frame_target_time) { - Callback callback; - - { - std::lock_guard lock(callback_mutex_); - callback = std::move(callback_); - } - - if (!callback) { - return; - } - - task_runners_.GetUITaskRunner()->PostTask( - [callback, frame_start_time, frame_target_time]() { - // Note: The tag name must be "VSYNC" (it is special) so that the - // "Highlight - // Vsync" checkbox in the timeline can be enabled. - TRACE_EVENT0("flutter", "VSYNC"); - callback(frame_start_time, frame_target_time); - }); -} - } // namespace shell diff --git a/shell/common/vsync_waiter.h b/shell/common/vsync_waiter.h index 82231fdf4f853..77319ed8b6966 100644 --- a/shell/common/vsync_waiter.h +++ b/shell/common/vsync_waiter.h @@ -6,10 +6,7 @@ #define FLUTTER_SHELL_COMMON_VSYNC_WAITER_H_ #include -#include -#include -#include "flutter/common/task_runners.h" #include "lib/fxl/time/time_point.h" namespace shell { @@ -19,23 +16,9 @@ class VsyncWaiter { using Callback = std::function; - virtual ~VsyncWaiter(); - - void AsyncWaitForVsync(Callback callback); - - protected: - const blink::TaskRunners task_runners_; - std::mutex callback_mutex_; - Callback callback_; - - VsyncWaiter(blink::TaskRunners task_runners); + virtual void AsyncWaitForVsync(Callback callback) = 0; - virtual void AwaitVSync() = 0; - - void FireCallback(fxl::TimePoint frame_start_time, - fxl::TimePoint frame_target_time); - - FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiter); + virtual ~VsyncWaiter(); }; } // namespace shell diff --git a/shell/common/vsync_waiter_fallback.cc b/shell/common/vsync_waiter_fallback.cc index bcf061bb7615f..01c86cdedc6aa 100644 --- a/shell/common/vsync_waiter_fallback.cc +++ b/shell/common/vsync_waiter_fallback.cc @@ -4,6 +4,7 @@ #include "flutter/shell/common/vsync_waiter_fallback.h" +#include "flutter/common/threads.h" #include "lib/fxl/logging.h" namespace shell { @@ -20,25 +21,28 @@ fxl::TimePoint SnapToNextTick(fxl::TimePoint value, } // namespace -VsyncWaiterFallback::VsyncWaiterFallback(blink::TaskRunners task_runners) - : VsyncWaiter(std::move(task_runners)), - phase_(fxl::TimePoint::Now()), - weak_factory_(this) {} +VsyncWaiterFallback::VsyncWaiterFallback() + : phase_(fxl::TimePoint::Now()), weak_factory_(this) {} VsyncWaiterFallback::~VsyncWaiterFallback() = default; constexpr fxl::TimeDelta interval = fxl::TimeDelta::FromSecondsF(1.0 / 60.0); -void VsyncWaiterFallback::AwaitVSync() { +void VsyncWaiterFallback::AsyncWaitForVsync(Callback callback) { + FXL_DCHECK(!callback_); + callback_ = std::move(callback); + fxl::TimePoint now = fxl::TimePoint::Now(); fxl::TimePoint next = SnapToNextTick(now, phase_, interval); - task_runners_.GetUITaskRunner()->PostDelayedTask( + blink::Threads::UI()->PostDelayedTask( [self = weak_factory_.GetWeakPtr()] { - if (self) { - const auto frame_time = fxl::TimePoint::Now(); - self->FireCallback(frame_time, frame_time + interval); - } + if (!self) + return; + fxl::TimePoint frame_time = fxl::TimePoint::Now(); + Callback callback = std::move(self->callback_); + self->callback_ = Callback(); + callback(frame_time, frame_time + interval); }, next - now); } diff --git a/shell/common/vsync_waiter_fallback.h b/shell/common/vsync_waiter_fallback.h index d3cc8faaf6ce7..bfb7e118b1330 100644 --- a/shell/common/vsync_waiter_fallback.h +++ b/shell/common/vsync_waiter_fallback.h @@ -5,24 +5,25 @@ #ifndef FLUTTER_SHELL_COMMON_VSYNC_WAITER_FALLBACK_H_ #define FLUTTER_SHELL_COMMON_VSYNC_WAITER_FALLBACK_H_ +#include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/vsync_waiter.h" #include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" #include "lib/fxl/time/time_point.h" namespace shell { -class VsyncWaiterFallback final : public VsyncWaiter { +class VsyncWaiterFallback : public VsyncWaiter { public: - VsyncWaiterFallback(blink::TaskRunners task_runners); - + VsyncWaiterFallback(); ~VsyncWaiterFallback() override; + void AsyncWaitForVsync(Callback callback) override; + private: fxl::TimePoint phase_; - fxl::WeakPtrFactory weak_factory_; + Callback callback_; - void AwaitVSync() override; + fml::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterFallback); }; diff --git a/shell/gpu/BUILD.gn b/shell/gpu/BUILD.gn index cd093e1238f7f..c050e120b0a10 100644 --- a/shell/gpu/BUILD.gn +++ b/shell/gpu/BUILD.gn @@ -6,17 +6,14 @@ import("$flutter_root/shell/config.gni") source_set("gpu") { sources = [ + "gpu_rasterizer.cc", + "gpu_rasterizer.h", + "gpu_surface_gl.cc", + "gpu_surface_gl.h", "gpu_surface_software.cc", "gpu_surface_software.h", ] - if (!is_fuchsia) { - sources += [ - "gpu_surface_gl.cc", - "gpu_surface_gl.h", - ] - } - if (shell_enable_vulkan) { sources += [ "gpu_surface_vulkan.cc", diff --git a/shell/gpu/gpu_rasterizer.cc b/shell/gpu/gpu_rasterizer.cc new file mode 100644 index 0000000000000..3424f989b3205 --- /dev/null +++ b/shell/gpu/gpu_rasterizer.cc @@ -0,0 +1,168 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "gpu_rasterizer.h" + +#include +#include + +#include "flutter/common/threads.h" +#include "flutter/glue/trace_event.h" +#include "flutter/shell/common/picture_serializer.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/shell.h" +#include "third_party/skia/include/core/SkPicture.h" + +namespace shell { + +GPURasterizer::GPURasterizer(std::unique_ptr info) + : compositor_context_(std::move(info)), weak_factory_(this) {} + +GPURasterizer::~GPURasterizer() = default; + +fml::WeakPtr GPURasterizer::GetWeakRasterizerPtr() { + return weak_factory_.GetWeakPtr(); +} + +void GPURasterizer::Setup(std::unique_ptr surface, + fxl::Closure continuation, + fxl::AutoResetWaitableEvent* setup_completion_event) { + surface_ = std::move(surface); + compositor_context_.OnGrContextCreated(); + + continuation(); + + setup_completion_event->Signal(); +} + +void GPURasterizer::Clear(SkColor color, const SkISize& size) { + if (surface_ == nullptr) { + return; + } + + auto frame = surface_->AcquireFrame(size); + + if (frame == nullptr) { + return; + } + + SkCanvas* canvas = frame->SkiaCanvas(); + + if (canvas == nullptr) { + return; + } + + canvas->clear(color); + + frame->Submit(); +} + +void GPURasterizer::Teardown( + fxl::AutoResetWaitableEvent* teardown_completion_event) { + compositor_context_.OnGrContextDestroyed(); + if (surface_) { + surface_.reset(); + } + last_layer_tree_.reset(); + teardown_completion_event->Signal(); +} + +flow::LayerTree* GPURasterizer::GetLastLayerTree() { + return last_layer_tree_.get(); +} + +void GPURasterizer::DrawLastLayerTree() { + if (!last_layer_tree_ || !surface_) { + return; + } + DrawToSurface(*last_layer_tree_); +} + +flow::TextureRegistry& GPURasterizer::GetTextureRegistry() { + return compositor_context_.texture_registry(); +} + +void GPURasterizer::Draw( + fxl::RefPtr> pipeline) { + TRACE_EVENT0("flutter", "GPURasterizer::Draw"); + + flutter::Pipeline::Consumer consumer = + std::bind(&GPURasterizer::DoDraw, this, std::placeholders::_1); + + // Consume as many pipeline items as possible. But yield the event loop + // between successive tries. + switch (pipeline->Consume(consumer)) { + case flutter::PipelineConsumeResult::MoreAvailable: { + auto weak_this = weak_factory_.GetWeakPtr(); + blink::Threads::Gpu()->PostTask([weak_this, pipeline]() { + if (weak_this) { + weak_this->Draw(pipeline); + } + }); + break; + } + default: + break; + } +} + +void GPURasterizer::DoDraw(std::unique_ptr layer_tree) { + if (!layer_tree || !surface_) { + return; + } + + // There is no way for the compositor to know how long the layer tree + // construction took. Fortunately, the layer tree does. Grab that time + // for instrumentation. + compositor_context_.engine_time().SetLapTime(layer_tree->construction_time()); + + DrawToSurface(*layer_tree); + + NotifyNextFrameOnce(); + + last_layer_tree_ = std::move(layer_tree); +} + +void GPURasterizer::DrawToSurface(flow::LayerTree& layer_tree) { + auto frame = surface_->AcquireFrame(layer_tree.frame_size()); + + if (frame == nullptr) { + return; + } + + auto canvas = frame->SkiaCanvas(); + + if (canvas == nullptr) { + return; + } + + auto compositor_frame = + compositor_context_.AcquireFrame(surface_->GetContext(), canvas); + + canvas->clear(SK_ColorBLACK); + + layer_tree.Raster(compositor_frame); + + frame->Submit(); +} + +void GPURasterizer::AddNextFrameCallback(fxl::Closure nextFrameCallback) { + nextFrameCallback_ = nextFrameCallback; +} + +void GPURasterizer::NotifyNextFrameOnce() { + if (nextFrameCallback_) { + blink::Threads::Platform()->PostTask([callback = nextFrameCallback_] { + TRACE_EVENT0("flutter", "GPURasterizer::NotifyNextFrameOnce"); + callback(); + }); + nextFrameCallback_ = nullptr; + } +} + +void GPURasterizer::SetTextureRegistry(flow::TextureRegistry* textureRegistry) { + compositor_context_.SetTextureRegistry(textureRegistry); +} + +} // namespace shell diff --git a/shell/gpu/gpu_rasterizer.h b/shell/gpu/gpu_rasterizer.h new file mode 100644 index 0000000000000..ad16ee2c47989 --- /dev/null +++ b/shell/gpu/gpu_rasterizer.h @@ -0,0 +1,68 @@ +// Copyright 2015 The Chromium 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 SHELL_GPU_DIRECT_GPU_RASTERIZER_H_ +#define SHELL_GPU_DIRECT_GPU_RASTERIZER_H_ + +#include "flutter/flow/compositor_context.h" +#include "flutter/shell/common/rasterizer.h" +#include "lib/fxl/memory/weak_ptr.h" +#include "lib/fxl/synchronization/waitable_event.h" + +namespace shell { + +class Surface; + +class GPURasterizer : public Rasterizer { + public: + GPURasterizer(std::unique_ptr info); + + ~GPURasterizer() override; + + void Setup(std::unique_ptr surface, + fxl::Closure continuation, + fxl::AutoResetWaitableEvent* setup_completion_event) override; + + void Clear(SkColor color, const SkISize& size) override; + + void Teardown( + fxl::AutoResetWaitableEvent* teardown_completion_event) override; + + fml::WeakPtr GetWeakRasterizerPtr() override; + + flow::LayerTree* GetLastLayerTree() override; + + void DrawLastLayerTree() override; + + flow::TextureRegistry& GetTextureRegistry() override; + + void Draw(fxl::RefPtr> pipeline) override; + + // Set a callback to be called once when the next frame is drawn. + void AddNextFrameCallback(fxl::Closure nextFrameCallback) override; + + void SetTextureRegistry(flow::TextureRegistry* textureRegistry) override; + + private: + std::unique_ptr surface_; + flow::CompositorContext compositor_context_; + std::unique_ptr last_layer_tree_; + // A closure to be called when the underlaying surface presents a frame the + // next time. NULL if there is no callback or the callback was set back to + // NULL after being called. + fxl::Closure nextFrameCallback_; + fml::WeakPtrFactory weak_factory_; + + void DoDraw(std::unique_ptr layer_tree); + + void DrawToSurface(flow::LayerTree& layer_tree); + + void NotifyNextFrameOnce(); + + FXL_DISALLOW_COPY_AND_ASSIGN(GPURasterizer); +}; + +} // namespace shell + +#endif // SHELL_GPU_DIRECT_GPU_RASTERIZER_H_ diff --git a/shell/gpu/gpu_surface_gl.cc b/shell/gpu/gpu_surface_gl.cc index 284a10e413b46..331fd188a9ed3 100644 --- a/shell/gpu/gpu_surface_gl.cc +++ b/shell/gpu/gpu_surface_gl.cc @@ -72,8 +72,6 @@ GPUSurfaceGL::~GPUSurfaceGL() { return; } - GetCompositorContext().OnGrContextDestroyed(); - onscreen_surface_ = nullptr; context_->releaseResourcesAndAbandonContext(); context_ = nullptr; @@ -212,11 +210,12 @@ std::unique_ptr GPUSurfaceGL::AcquireFrame(const SkISize& size) { return nullptr; } - SurfaceFrame::SubmitCallback submit_callback = [weak = weak_factory_ - .GetWeakPtr()]( - const SurfaceFrame& surface_frame, SkCanvas* canvas) { - return weak ? weak->PresentSurface(canvas) : false; - }; + auto weak_this = weak_factory_.GetWeakPtr(); + + SurfaceFrame::SubmitCallback submit_callback = + [weak_this](const SurfaceFrame& surface_frame, SkCanvas* canvas) { + return weak_this ? weak_this->PresentSurface(canvas) : false; + }; return std::make_unique(surface, submit_callback); } diff --git a/shell/gpu/gpu_surface_gl.h b/shell/gpu/gpu_surface_gl.h index abc9f46aee297..5cf092dae66c5 100644 --- a/shell/gpu/gpu_surface_gl.h +++ b/shell/gpu/gpu_surface_gl.h @@ -5,9 +5,10 @@ #ifndef SHELL_GPU_GPU_SURFACE_GL_H_ #define SHELL_GPU_GPU_SURFACE_GL_H_ +#include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/surface.h" +#include "flutter/synchronization/debug_thread_checker.h" #include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" #include "third_party/skia/include/gpu/GrContext.h" namespace shell { @@ -43,7 +44,7 @@ class GPUSurfaceGL : public Surface { sk_sp onscreen_surface_; sk_sp offscreen_surface_; bool valid_ = false; - fxl::WeakPtrFactory weak_factory_; + fml::WeakPtrFactory weak_factory_; bool CreateOrUpdateSurfaces(const SkISize& size); diff --git a/shell/gpu/gpu_surface_software.cc b/shell/gpu/gpu_surface_software.cc index ea8c827b22405..e340e605652dd 100644 --- a/shell/gpu/gpu_surface_software.cc +++ b/shell/gpu/gpu_surface_software.cc @@ -18,13 +18,20 @@ bool GPUSurfaceSoftware::IsValid() { return delegate_ != nullptr; } +bool GPUSurfaceSoftware::SupportsScaling() const { + return true; +} + std::unique_ptr GPUSurfaceSoftware::AcquireFrame( const SkISize& logical_size) { if (!IsValid()) { return nullptr; } - const auto size = SkISize::Make(logical_size.width(), logical_size.height()); + // Check if we need to support surface scaling. + const auto scale = SupportsScaling() ? GetScale() : 1.0; + const auto size = SkISize::Make(logical_size.width() * scale, + logical_size.height() * scale); sk_sp backing_store = delegate_->AcquireBackingStore(size); @@ -41,10 +48,12 @@ std::unique_ptr GPUSurfaceSoftware::AcquireFrame( // irrespective of surface scaling. SkCanvas* canvas = backing_store->getCanvas(); canvas->resetMatrix(); + canvas->scale(scale, scale); - SurfaceFrame::SubmitCallback on_submit = - [self = weak_factory_.GetWeakPtr()](const SurfaceFrame& surface_frame, - SkCanvas* canvas) -> bool { + SurfaceFrame::SubmitCallback + on_submit = [self = weak_factory_.GetWeakPtr()]( + const SurfaceFrame& surface_frame, SkCanvas* canvas) + ->bool { // If the surface itself went away, there is nothing more to do. if (!self || !self->IsValid() || canvas == nullptr) { return false; diff --git a/shell/gpu/gpu_surface_software.h b/shell/gpu/gpu_surface_software.h index 238754f312b80..f7312153db8bc 100644 --- a/shell/gpu/gpu_surface_software.h +++ b/shell/gpu/gpu_surface_software.h @@ -5,9 +5,9 @@ #ifndef FLUTTER_SHELL_GPU_GPU_SURFACE_SOFTWARE_H_ #define FLUTTER_SHELL_GPU_GPU_SURFACE_SOFTWARE_H_ +#include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/surface.h" #include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" #include "third_party/skia/include/core/SkSurface.h" namespace shell { @@ -30,9 +30,12 @@ class GPUSurfaceSoftware : public Surface { GrContext* GetContext() override; + bool SupportsScaling() const override; + private: GPUSurfaceSoftwareDelegate* delegate_; - fxl::WeakPtrFactory weak_factory_; + + fml::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceSoftware); }; diff --git a/shell/gpu/gpu_surface_vulkan.h b/shell/gpu/gpu_surface_vulkan.h index f1e25fbe987b8..eafed43a6296d 100644 --- a/shell/gpu/gpu_surface_vulkan.h +++ b/shell/gpu/gpu_surface_vulkan.h @@ -6,12 +6,11 @@ #define SHELL_GPU_GPU_SURFACE_VULKAN_H_ #include - +#include "flutter/fml/memory/weak_ptr.h" #include "flutter/shell/common/surface.h" #include "flutter/vulkan/vulkan_native_surface.h" #include "flutter/vulkan/vulkan_window.h" #include "lib/fxl/macros.h" -#include "lib/fxl/memory/weak_ptr.h" namespace shell { @@ -30,7 +29,7 @@ class GPUSurfaceVulkan : public Surface { private: vulkan::VulkanWindow window_; - fxl::WeakPtrFactory weak_factory_; + fml::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceVulkan); }; diff --git a/shell/platform/BUILD.gn b/shell/platform/BUILD.gn index ae3b1003f22fe..4b1e1a9e0bfeb 100644 --- a/shell/platform/BUILD.gn +++ b/shell/platform/BUILD.gn @@ -13,11 +13,13 @@ group("platform") { ] } else if (is_linux) { deps = [ + "linux", "embedder", ] } else if (is_win) { - # There is no platform target on windows. Instead, only a tester is used. - deps = [] + deps = [ + "win" + ] } else { assert(false, "Unknown/Unsupported platform.") } diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 129c877faed0f..d9744ad890caa 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -17,25 +17,21 @@ shared_library("flutter_shell_native") { "android_context_gl.h", "android_environment_gl.cc", "android_environment_gl.h", - "android_external_texture_gl.cc", "android_external_texture_gl.h", + "android_external_texture_gl.cc", "android_native_window.cc", "android_native_window.h", - "android_shell_holder.cc", - "android_shell_holder.h", "android_surface.cc", "android_surface.h", "android_surface_gl.cc", "android_surface_gl.h", - "android_surface_software.cc", "android_surface_software.h", - "apk_asset_provider.cc", + "android_surface_software.cc", "apk_asset_provider.h", + "apk_asset_provider.cc", "flutter_main.cc", "flutter_main.h", "library_loader.cc", - "platform_message_response_android.cc", - "platform_message_response_android.h", "platform_view_android.cc", "platform_view_android.h", "platform_view_android_jni.cc", @@ -45,10 +41,10 @@ shared_library("flutter_shell_native") { ] deps = [ - "$flutter_root/assets", "$flutter_root/common", "$flutter_root/flow", "$flutter_root/fml", + "$flutter_root/assets", "$flutter_root/lib/ui", "$flutter_root/runtime", "$flutter_root/shell/common", @@ -63,7 +59,9 @@ shared_library("flutter_shell_native") { deps += [ "//third_party/dart/runtime:libdart_precompiled_runtime" ] } - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] defines = [] diff --git a/shell/platform/android/android_context_gl.cc b/shell/platform/android/android_context_gl.cc index 6338dc96908e1..f54629f8644b9 100644 --- a/shell/platform/android/android_context_gl.cc +++ b/shell/platform/android/android_context_gl.cc @@ -3,13 +3,9 @@ // found in the LICENSE file. #include "flutter/shell/platform/android/android_context_gl.h" - #include - #include -#include "flutter/fml/trace_event.h" - namespace shell { template @@ -69,17 +65,19 @@ static EGLResult CreateContext(EGLDisplay display, return {context != EGL_NO_CONTEXT, context}; } -static EGLResult ChooseEGLConfiguration(EGLDisplay display) { +static EGLResult ChooseEGLConfiguration( + EGLDisplay display, + PlatformView::SurfaceConfig config) { EGLint attributes[] = { // clang-format off EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_ALPHA_SIZE, 8, - EGL_DEPTH_SIZE, 0, - EGL_STENCIL_SIZE, 0, + EGL_RED_SIZE, config.red_bits, + EGL_GREEN_SIZE, config.green_bits, + EGL_BLUE_SIZE, config.blue_bits, + EGL_ALPHA_SIZE, config.alpha_bits, + EGL_DEPTH_SIZE, config.depth_bits, + EGL_STENCIL_SIZE, config.stencil_bits, EGL_NONE, // termination sentinel // clang-format on }; @@ -144,6 +142,7 @@ bool AndroidContextGL::CreatePBufferSurface() { } AndroidContextGL::AndroidContextGL(fxl::RefPtr env, + PlatformView::SurfaceConfig config, const AndroidContextGL* share_context) : environment_(env), window_(nullptr), @@ -159,7 +158,8 @@ AndroidContextGL::AndroidContextGL(fxl::RefPtr env, // Choose a valid configuration. - std::tie(success, config_) = ChooseEGLConfiguration(environment_->Display()); + std::tie(success, config_) = + ChooseEGLConfiguration(environment_->Display(), config); if (!success) { FXL_LOG(ERROR) << "Could not choose an EGL configuration."; diff --git a/shell/platform/android/android_context_gl.h b/shell/platform/android/android_context_gl.h index b29851b34564d..207f621c66bd1 100644 --- a/shell/platform/android/android_context_gl.h +++ b/shell/platform/android/android_context_gl.h @@ -44,6 +44,7 @@ class AndroidContextGL : public fxl::RefCountedThreadSafe { bool valid_; AndroidContextGL(fxl::RefPtr env, + PlatformView::SurfaceConfig config, const AndroidContextGL* share_context = nullptr); ~AndroidContextGL(); diff --git a/shell/platform/android/android_external_texture_gl.cc b/shell/platform/android/android_external_texture_gl.cc index 35db9cbbfdb95..02a40c22474a1 100644 --- a/shell/platform/android/android_external_texture_gl.cc +++ b/shell/platform/android/android_external_texture_gl.cc @@ -5,7 +5,7 @@ #include "flutter/shell/platform/android/android_external_texture_gl.h" #include - +#include "flutter/common/threads.h" #include "flutter/shell/platform/android/platform_view_android_jni.h" #include "third_party/skia/include/gpu/GrTexture.h" @@ -19,14 +19,17 @@ AndroidExternalTextureGL::AndroidExternalTextureGL( AndroidExternalTextureGL::~AndroidExternalTextureGL() = default; void AndroidExternalTextureGL::OnGrContextCreated() { + ASSERT_IS_GPU_THREAD; state_ = AttachmentState::uninitialized; } void AndroidExternalTextureGL::MarkNewFrameAvailable() { + ASSERT_IS_GPU_THREAD; new_frame_ready_ = true; } void AndroidExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds) { + ASSERT_IS_GPU_THREAD; if (state_ == AttachmentState::detached) { return; } @@ -39,8 +42,7 @@ void AndroidExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds) { Update(); new_frame_ready_ = false; } - GrGLTextureInfo textureInfo = {GL_TEXTURE_EXTERNAL_OES, texture_name_, - GL_RGBA8_OES}; + GrGLTextureInfo textureInfo = {GL_TEXTURE_EXTERNAL_OES, texture_name_, GL_RGBA8_OES}; GrBackendTexture backendTexture(1, 1, GrMipMapped::kNo, textureInfo); sk_sp image = SkImage::MakeFromTexture( canvas.getGrContext(), backendTexture, kTopLeft_GrSurfaceOrigin, @@ -80,6 +82,7 @@ void AndroidExternalTextureGL::UpdateTransform() { } void AndroidExternalTextureGL::OnGrContextDestroyed() { + ASSERT_IS_GPU_THREAD; if (state_ == AttachmentState::attached) { Detach(); } diff --git a/shell/platform/android/android_external_texture_gl.h b/shell/platform/android/android_external_texture_gl.h index 67d6541d964c2..df890b91c827f 100644 --- a/shell/platform/android/android_external_texture_gl.h +++ b/shell/platform/android/android_external_texture_gl.h @@ -25,7 +25,8 @@ class AndroidExternalTextureGL : public flow::Texture { virtual void OnGrContextDestroyed() override; - void MarkNewFrameAvailable() override; + // Called on GPU thread. + void MarkNewFrameAvailable(); private: void Attach(jint textureName); diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc deleted file mode 100644 index 7dc454f1fb74a..0000000000000 --- a/shell/platform/android/android_shell_holder.cc +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright 2018 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. - -#define FML_USED_ON_EMBEDDER - -#include "flutter/shell/platform/android/android_shell_holder.h" - -#include -#include - -#include -#include -#include - -#include "flutter/fml/message_loop.h" -#include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/platform/android/platform_view_android.h" -#include "lib/fxl/functional/make_copyable.h" - -namespace shell { - -AndroidShellHolder::AndroidShellHolder( - blink::Settings settings, - fml::jni::JavaObjectWeakGlobalRef java_object) - : settings_(std::move(settings)), java_object_(java_object) { - static size_t shell_count = 1; - auto thread_label = std::to_string(shell_count++); - - thread_host_ = {thread_label, ThreadHost::Type::UI | ThreadHost::Type::GPU | - ThreadHost::Type::IO}; - - fml::WeakPtr weak_platform_view; - Shell::CreateCallback on_create_platform_view = - [java_object, &weak_platform_view](Shell& shell) { - auto platform_view_android = std::make_unique( - shell, // delegate - shell.GetTaskRunners(), // task runners - java_object, // java object handle for JNI interop - shell.GetSettings() - .enable_software_rendering // use software rendering - ); - weak_platform_view = platform_view_android->GetWeakPtr(); - return platform_view_android; - }; - - Shell::CreateCallback on_create_rasterizer = [](Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }; - - // The current thread will be used as the platform thread. Ensure that the - // message loop is initialized. - fml::MessageLoop::EnsureInitializedForCurrentThread(); - - blink::TaskRunners task_runners( - thread_label, // label - fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform - thread_host_.gpu_thread->GetTaskRunner(), // gpu - thread_host_.ui_thread->GetTaskRunner(), // ui - thread_host_.io_thread->GetTaskRunner() // io - ); - - shell_ = - Shell::Create(task_runners, // task runners - settings_, // settings - on_create_platform_view, // platform view create callback - on_create_rasterizer // rasterizer create callback - ); - - platform_view_ = weak_platform_view; - FXL_DCHECK(platform_view_); - - is_valid_ = shell_ != nullptr; - - if (is_valid_) { - task_runners.GetGPUTaskRunner()->PostTask( - []() { ::setpriority(PRIO_PROCESS, gettid(), -2); }); - task_runners.GetUITaskRunner()->PostTask( - []() { ::setpriority(PRIO_PROCESS, gettid(), -1); }); - } -} - -AndroidShellHolder::~AndroidShellHolder() = default; - -bool AndroidShellHolder::IsValid() const { - return is_valid_; -} - -const blink::Settings& AndroidShellHolder::GetSettings() const { - return settings_; -} - -void AndroidShellHolder::Launch(RunConfiguration config) { - if (!IsValid()) { - return; - } - - shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - fxl::MakeCopyable([engine = shell_->GetEngine(), // - config = std::move(config) // - ]() mutable { - if (engine) { - if (!engine->Run(std::move(config))) { - FXL_LOG(ERROR) << "Could not launch engine in configuration."; - } - } - })); -} - -void AndroidShellHolder::SetViewportMetrics( - const blink::ViewportMetrics& metrics) { - if (!IsValid()) { - return; - } - - shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - [engine = shell_->GetEngine(), metrics]() { - if (engine) { - engine->SetViewportMetrics(metrics); - } - }); -} - -void AndroidShellHolder::DispatchPointerDataPacket( - std::unique_ptr packet) { - if (!IsValid()) { - return; - } - - shell_->GetTaskRunners().GetUITaskRunner()->PostTask(fxl::MakeCopyable( - [engine = shell_->GetEngine(), packet = std::move(packet)] { - if (engine) { - engine->DispatchPointerDataPacket(*packet); - } - })); -} - -Rasterizer::Screenshot AndroidShellHolder::Screenshot( - Rasterizer::ScreenshotType type, - bool base64_encode) { - if (!IsValid()) { - return {nullptr, SkISize::MakeEmpty()}; - } - return shell_->Screenshot(type, base64_encode); -} - -fml::WeakPtr AndroidShellHolder::GetPlatformView() { - FXL_DCHECK(platform_view_); - return platform_view_; -} - -void AndroidShellHolder::UpdateAssetManager( - fxl::RefPtr asset_manager) { - if (!IsValid() || !asset_manager) { - return; - } - - shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - [engine = shell_->GetEngine(), - asset_manager = std::move(asset_manager)]() { - if (engine) { - if (!engine->UpdateAssetManager(std::move(asset_manager))) { - FXL_DLOG(ERROR) << "Could not update asset asset manager."; - } - } - }); -} - -} // namespace shell diff --git a/shell/platform/android/android_shell_holder.h b/shell/platform/android/android_shell_holder.h deleted file mode 100644 index e0905f0f9e42e..0000000000000 --- a/shell/platform/android/android_shell_holder.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018 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_ANDROID_ANDROID_SHELL_HOLDER_H_ -#define FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SHELL_HOLDER_H_ - -#include - -#include "flutter/fml/platform/android/jni_weak_ref.h" -#include "flutter/lib/ui/window/viewport_metrics.h" -#include "flutter/shell/common/run_configuration.h" -#include "flutter/shell/common/shell.h" -#include "flutter/shell/common/thread_host.h" -#include "flutter/shell/platform/android/platform_view_android.h" -#include "lib/fxl/files/unique_fd.h" -#include "lib/fxl/macros.h" - -namespace shell { - -class AndroidShellHolder { - public: - AndroidShellHolder(blink::Settings settings, - fml::jni::JavaObjectWeakGlobalRef java_object); - - ~AndroidShellHolder(); - - bool IsValid() const; - - void Launch(RunConfiguration configuration); - - void SetViewportMetrics(const blink::ViewportMetrics& metrics); - - void DispatchPointerDataPacket( - std::unique_ptr packet); - - const blink::Settings& GetSettings() const; - - fml::WeakPtr GetPlatformView(); - - Rasterizer::Screenshot Screenshot(Rasterizer::ScreenshotType type, - bool base64_encode); - - void UpdateAssetManager(fxl::RefPtr asset_manager); - - private: - const blink::Settings settings_; - const fml::jni::JavaObjectWeakGlobalRef java_object_; - fml::WeakPtr platform_view_; - ThreadHost thread_host_; - std::unique_ptr shell_; - bool is_valid_ = false; - - FXL_DISALLOW_COPY_AND_ASSIGN(AndroidShellHolder); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_PLATFORM_ANDROID_ANDROID_SHELL_HOLDER_H_ diff --git a/shell/platform/android/android_surface.cc b/shell/platform/android/android_surface.cc index a8b41bacbf7c5..4dd08609da370 100644 --- a/shell/platform/android/android_surface.cc +++ b/shell/platform/android/android_surface.cc @@ -4,32 +4,8 @@ #include "flutter/shell/platform/android/android_surface.h" -#include - -#include "flutter/shell/platform/android/android_surface_gl.h" -#include "flutter/shell/platform/android/android_surface_software.h" -#if SHELL_ENABLE_VULKAN -#include "flutter/shell/platform/android/android_surface_vulkan.h" -#endif // SHELL_ENABLE_VULKAN - namespace shell { -std::unique_ptr AndroidSurface::Create( - bool use_software_rendering) { - if (use_software_rendering) { - auto software_surface = std::make_unique(); - return software_surface->IsValid() ? std::move(software_surface) : nullptr; - } -#if SHELL_ENABLE_VULKAN - auto vulkan_surface = std::make_unique(); - return vulkan_surface->IsValid() ? std::move(vulkan_surface) : nullptr; -#else // SHELL_ENABLE_VULKAN - auto gl_surface = std::make_unique(); - return gl_surface->IsOffscreenContextValid() ? std::move(gl_surface) - : nullptr; -#endif // SHELL_ENABLE_VULKAN -} - AndroidSurface::~AndroidSurface() = default; } // namespace shell diff --git a/shell/platform/android/android_surface.h b/shell/platform/android/android_surface.h index 858b07eb45d9f..2425a61e20707 100644 --- a/shell/platform/android/android_surface.h +++ b/shell/platform/android/android_surface.h @@ -19,8 +19,6 @@ namespace shell { class AndroidSurface { public: - static std::unique_ptr Create(bool use_software_rendering); - virtual ~AndroidSurface(); virtual bool IsValid() const = 0; @@ -29,11 +27,14 @@ class AndroidSurface { virtual std::unique_ptr CreateGPUSurface() = 0; + virtual SkISize OnScreenSurfaceSize() const = 0; + virtual bool OnScreenSurfaceResize(const SkISize& size) const = 0; virtual bool ResourceContextMakeCurrent() = 0; - virtual bool SetNativeWindow(fxl::RefPtr window) = 0; + virtual bool SetNativeWindow(fxl::RefPtr window, + PlatformView::SurfaceConfig config = {}) = 0; }; } // namespace shell diff --git a/shell/platform/android/android_surface_gl.cc b/shell/platform/android/android_surface_gl.cc index 274b652a97b74..f30ac1272b043 100644 --- a/shell/platform/android/android_surface_gl.cc +++ b/shell/platform/android/android_surface_gl.cc @@ -6,12 +6,14 @@ #include +#include "flutter/common/threads.h" #include "lib/fxl/logging.h" #include "lib/fxl/memory/ref_ptr.h" namespace shell { -static fxl::RefPtr GlobalResourceLoadingContext() { +static fxl::RefPtr GlobalResourceLoadingContext( + PlatformView::SurfaceConfig offscreen_config) { // AndroidSurfaceGL instances are only ever created on the platform thread. So // there is no need to lock here. @@ -27,7 +29,11 @@ static fxl::RefPtr GlobalResourceLoadingContext() { return nullptr; } - auto context = fxl::MakeRefCounted(environment); + // TODO(chinmaygarde): We should check that the configurations are stable + // across multiple invocations. + + auto context = + fxl::MakeRefCounted(environment, offscreen_config); if (!context->IsValid()) { return nullptr; @@ -37,9 +43,10 @@ static fxl::RefPtr GlobalResourceLoadingContext() { return global_context; } -AndroidSurfaceGL::AndroidSurfaceGL() { +AndroidSurfaceGL::AndroidSurfaceGL( + PlatformView::SurfaceConfig offscreen_config) { // Acquire the offscreen context. - offscreen_context_ = GlobalResourceLoadingContext(); + offscreen_context_ = GlobalResourceLoadingContext(offscreen_config); if (!offscreen_context_ || !offscreen_context_->IsValid()) { offscreen_context_ = nullptr; @@ -53,9 +60,14 @@ bool AndroidSurfaceGL::IsOffscreenContextValid() const { } void AndroidSurfaceGL::TeardownOnScreenContext() { - if (onscreen_context_) { - onscreen_context_->ClearCurrent(); - } + fxl::AutoResetWaitableEvent latch; + blink::Threads::Gpu()->PostTask([this, &latch]() { + if (IsValid()) { + GLContextClearCurrent(); + } + latch.Signal(); + }); + latch.Wait(); onscreen_context_ = nullptr; } @@ -72,6 +84,11 @@ std::unique_ptr AndroidSurfaceGL::CreateGPUSurface() { return surface->IsValid() ? std::move(surface) : nullptr; } +SkISize AndroidSurfaceGL::OnScreenSurfaceSize() const { + FXL_DCHECK(onscreen_context_ && onscreen_context_->IsValid()); + return onscreen_context_->GetSize(); +} + bool AndroidSurfaceGL::OnScreenSurfaceResize(const SkISize& size) const { FXL_DCHECK(onscreen_context_ && onscreen_context_->IsValid()); return onscreen_context_->Resize(size); @@ -82,8 +99,8 @@ bool AndroidSurfaceGL::ResourceContextMakeCurrent() { return offscreen_context_->MakeCurrent(); } -bool AndroidSurfaceGL::SetNativeWindow( - fxl::RefPtr window) { +bool AndroidSurfaceGL::SetNativeWindow(fxl::RefPtr window, + PlatformView::SurfaceConfig config) { // In any case, we want to get rid of our current onscreen context. onscreen_context_ = nullptr; @@ -95,7 +112,7 @@ bool AndroidSurfaceGL::SetNativeWindow( // Create the onscreen context. onscreen_context_ = fxl::MakeRefCounted( - offscreen_context_->Environment(), + offscreen_context_->Environment(), config, offscreen_context_.get() /* sharegroup */); if (!onscreen_context_->IsValid()) { diff --git a/shell/platform/android/android_surface_gl.h b/shell/platform/android/android_surface_gl.h index e26f2bf50d3a9..08aee081c8266 100644 --- a/shell/platform/android/android_surface_gl.h +++ b/shell/platform/android/android_surface_gl.h @@ -16,43 +16,35 @@ namespace shell { -class AndroidSurfaceGL final : public GPUSurfaceGLDelegate, - public AndroidSurface { +class AndroidSurfaceGL : public GPUSurfaceGLDelegate, public AndroidSurface { public: - AndroidSurfaceGL(); + explicit AndroidSurfaceGL(PlatformView::SurfaceConfig offscreen_config); ~AndroidSurfaceGL() override; - bool IsOffscreenContextValid() const; - - // |shell::AndroidSurface| bool IsValid() const override; - // |shell::AndroidSurface| + bool IsOffscreenContextValid() const; + std::unique_ptr CreateGPUSurface() override; - // |shell::AndroidSurface| void TeardownOnScreenContext() override; - // |shell::AndroidSurface| + SkISize OnScreenSurfaceSize() const override; + bool OnScreenSurfaceResize(const SkISize& size) const override; - // |shell::AndroidSurface| bool ResourceContextMakeCurrent() override; - // |shell::AndroidSurface| - bool SetNativeWindow(fxl::RefPtr window) override; + bool SetNativeWindow(fxl::RefPtr window, + PlatformView::SurfaceConfig config) override; - // |shell::GPUSurfaceGLDelegate| bool GLContextMakeCurrent() override; - // |shell::GPUSurfaceGLDelegate| bool GLContextClearCurrent() override; - // |shell::GPUSurfaceGLDelegate| bool GLContextPresent() override; - // |shell::GPUSurfaceGLDelegate| intptr_t GLContextFBO() const override; private: diff --git a/shell/platform/android/android_surface_software.cc b/shell/platform/android/android_surface_software.cc index 4b1378802d9e4..68bf99b27ba56 100644 --- a/shell/platform/android/android_surface_software.cc +++ b/shell/platform/android/android_surface_software.cc @@ -3,14 +3,15 @@ // found in the LICENSE file. #include "flutter/shell/platform/android/android_surface_software.h" +#include "flutter/common/threads.h" +#include "flutter/fml/platform/android/jni_weak_ref.h" +#include "flutter/fml/platform/android/scoped_java_ref.h" +#include "flutter/shell/platform/android/platform_view_android_jni.h" #include #include -#include "flutter/fml/platform/android/jni_weak_ref.h" -#include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/platform/android/platform_view_android_jni.h" #include "lib/fxl/logging.h" namespace shell { @@ -131,12 +132,17 @@ bool AndroidSurfaceSoftware::PresentBackingStore( void AndroidSurfaceSoftware::TeardownOnScreenContext() {} +SkISize AndroidSurfaceSoftware::OnScreenSurfaceSize() const { + return SkISize(); +} + bool AndroidSurfaceSoftware::OnScreenSurfaceResize(const SkISize& size) const { return true; } bool AndroidSurfaceSoftware::SetNativeWindow( - fxl::RefPtr window) { + fxl::RefPtr window, + PlatformView::SurfaceConfig config) { native_window_ = std::move(window); if (!(native_window_ && native_window_->IsValid())) return false; diff --git a/shell/platform/android/android_surface_software.h b/shell/platform/android/android_surface_software.h index 0f82fc5dfe154..76184b707cf74 100644 --- a/shell/platform/android/android_surface_software.h +++ b/shell/platform/android/android_surface_software.h @@ -13,39 +13,35 @@ namespace shell { -class AndroidSurfaceSoftware final : public AndroidSurface, - public GPUSurfaceSoftwareDelegate { +class AndroidSurfaceSoftware : public AndroidSurface, + public GPUSurfaceSoftwareDelegate { public: AndroidSurfaceSoftware(); ~AndroidSurfaceSoftware() override; - // |shell::AndroidSurface| bool IsValid() const override; - // |shell::AndroidSurface| bool ResourceContextMakeCurrent() override; - // |shell::AndroidSurface| std::unique_ptr CreateGPUSurface() override; - // |shell::AndroidSurface| - void TeardownOnScreenContext() override; + sk_sp AcquireBackingStore(const SkISize& size) override; - // |shell::AndroidSurface| - bool OnScreenSurfaceResize(const SkISize& size) const override; + bool PresentBackingStore(sk_sp backing_store) override; + + void TeardownOnScreenContext() override; - // |shell::AndroidSurface| - bool SetNativeWindow(fxl::RefPtr window) override; + SkISize OnScreenSurfaceSize() const override; - // |shell::GPUSurfaceSoftwareDelegate| - sk_sp AcquireBackingStore(const SkISize& size) override; + bool OnScreenSurfaceResize(const SkISize& size) const override; - // |shell::GPUSurfaceSoftwareDelegate| - bool PresentBackingStore(sk_sp backing_store) override; + bool SetNativeWindow(fxl::RefPtr window, + PlatformView::SurfaceConfig config) override; private: sk_sp sk_surface_; + fxl::RefPtr native_window_; SkColorType target_color_type_; SkAlphaType target_alpha_type_; diff --git a/shell/platform/android/android_surface_vulkan.cc b/shell/platform/android/android_surface_vulkan.cc index e8817690188c2..ccacf538b8781 100644 --- a/shell/platform/android/android_surface_vulkan.cc +++ b/shell/platform/android/android_surface_vulkan.cc @@ -21,12 +21,10 @@ bool AndroidSurfaceVulkan::IsValid() const { return proc_table_->HasAcquiredMandatoryProcAddresses(); } -// |shell::AndroidSurface| void AndroidSurfaceVulkan::TeardownOnScreenContext() { - // Nothing to do. + // } -// |shell::AndroidSurface| std::unique_ptr AndroidSurfaceVulkan::CreateGPUSurface() { if (!IsValid()) { return nullptr; @@ -54,20 +52,21 @@ std::unique_ptr AndroidSurfaceVulkan::CreateGPUSurface() { return gpu_surface; } -// |shell::AndroidSurface| +SkISize AndroidSurfaceVulkan::OnScreenSurfaceSize() const { + return native_window_ ? native_window_->GetSize() : SkISize::Make(0, 0); +} + bool AndroidSurfaceVulkan::OnScreenSurfaceResize(const SkISize& size) const { return true; } -// |shell::AndroidSurface| bool AndroidSurfaceVulkan::ResourceContextMakeCurrent() { - FXL_DLOG(ERROR) << "The vulkan backend does not support resource contexts."; return false; } -// |shell::AndroidSurface| bool AndroidSurfaceVulkan::SetNativeWindow( - fxl::RefPtr window) { + fxl::RefPtr window, + PlatformView::SurfaceConfig config) { native_window_ = std::move(window); return native_window_ && native_window_->IsValid(); } diff --git a/shell/platform/android/android_surface_vulkan.h b/shell/platform/android/android_surface_vulkan.h index fd3f493d49790..f1ecf610c8584 100644 --- a/shell/platform/android/android_surface_vulkan.h +++ b/shell/platform/android/android_surface_vulkan.h @@ -20,23 +20,20 @@ class AndroidSurfaceVulkan : public AndroidSurface { ~AndroidSurfaceVulkan() override; - // |shell::AndroidSurface| bool IsValid() const override; - // |shell::AndroidSurface| + void TeardownOnScreenContext() override; + std::unique_ptr CreateGPUSurface() override; - // |shell::AndroidSurface| - void TeardownOnScreenContext() override; + SkISize OnScreenSurfaceSize() const override; - // |shell::AndroidSurface| bool OnScreenSurfaceResize(const SkISize& size) const override; - // |shell::AndroidSurface| bool ResourceContextMakeCurrent() override; - // |shell::AndroidSurface| - bool SetNativeWindow(fxl::RefPtr window) override; + bool SetNativeWindow(fxl::RefPtr window, + PlatformView::SurfaceConfig config) override; private: fxl::RefPtr proc_table_; diff --git a/shell/platform/android/apk_asset_provider.cc b/shell/platform/android/apk_asset_provider.cc index 4cf6da16dc64f..fdd4910a12f4c 100644 --- a/shell/platform/android/apk_asset_provider.cc +++ b/shell/platform/android/apk_asset_provider.cc @@ -7,41 +7,32 @@ namespace blink { -APKAssetProvider::APKAssetProvider(JNIEnv* env, - jobject jassetManager, - std::string directory) - : directory_(std::move(directory)) { - assetManager_ = AAssetManager_fromJava(env, jassetManager); -} - -APKAssetProvider::~APKAssetProvider() = default; - -bool APKAssetProvider::IsValid() const { - return true; -} - bool APKAssetProvider::GetAsBuffer(const std::string& asset_name, - std::vector* data) const { + std::vector* data) { std::stringstream ss; ss << directory_.c_str() << "/" << asset_name; - AAsset* asset = - AAssetManager_open(assetManager_, ss.str().c_str(), AASSET_MODE_BUFFER); + AAsset* asset = AAssetManager_open(assetManager_, ss.str().c_str(), AASSET_MODE_BUFFER); if (!asset) { - return false; + return false; } uint8_t* buffer = (uint8_t*)AAsset_getBuffer(asset); if (!buffer) { FXL_LOG(ERROR) << "Got null trying to acquire buffer for asset:" << asset; - AAsset_close(asset); return false; } data->resize(AAsset_getLength(asset)); std::copy(buffer, buffer + data->size(), data->begin()); - AAsset_close(asset); return true; } +APKAssetProvider::~APKAssetProvider() {} + +APKAssetProvider::APKAssetProvider(JNIEnv* env, jobject jassetManager, std::string directory) + : directory_(std::move(directory)) { + assetManager_ = AAssetManager_fromJava(env, jassetManager); +} + } // namespace blink diff --git a/shell/platform/android/apk_asset_provider.h b/shell/platform/android/apk_asset_provider.h index 70ddbe454bc61..c40b1ed2a1866 100644 --- a/shell/platform/android/apk_asset_provider.h +++ b/shell/platform/android/apk_asset_provider.h @@ -5,35 +5,28 @@ #ifndef FLUTTER_ASSETS_APK_ASSET_PROVIDER_H_ #define FLUTTER_ASSETS_APK_ASSET_PROVIDER_H_ -#include #include +#include -#include "flutter/assets/asset_resolver.h" +#include "flutter/assets/asset_provider.h" #include "lib/fxl/memory/ref_counted.h" namespace blink { -class APKAssetProvider final : public AssetResolver { +class APKAssetProvider + : public AssetProvider { public: - explicit APKAssetProvider(JNIEnv* env, - jobject assetManager, - std::string directory); + explicit APKAssetProvider(JNIEnv* env, jobject assetManager, std::string directory); virtual ~APKAssetProvider(); - private: - AAssetManager* assetManager_; - const std::string directory_; - - // |blink::AssetResolver| - bool IsValid() const override; - - // |blink::AssetResolver| virtual bool GetAsBuffer(const std::string& asset_name, - std::vector* data) const override; + std::vector* data); - FXL_DISALLOW_COPY_AND_ASSIGN(APKAssetProvider); + private: + AAssetManager* assetManager_; + const std::string directory_; }; } // namespace blink -#endif // FLUTTER_ASSETS_APK_ASSET_PROVIDER_H \ No newline at end of file +#endif // FLUTTER_ASSETS_APK_ASSET_PROVIDER_H \ No newline at end of file diff --git a/shell/platform/android/flutter_main.cc b/shell/platform/android/flutter_main.cc index 08d97add93b87..6df346a128722 100644 --- a/shell/platform/android/flutter_main.cc +++ b/shell/platform/android/flutter_main.cc @@ -2,85 +2,38 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include "flutter/shell/platform/android/flutter_main.h" #include -#include "flutter/fml/message_loop.h" -#include "flutter/fml/paths.h" #include "flutter/fml/platform/android/jni_util.h" -#include "flutter/runtime/dart_vm.h" #include "flutter/runtime/start_up.h" #include "flutter/shell/common/shell.h" -#include "flutter/shell/common/switches.h" #include "lib/fxl/arraysize.h" #include "lib/fxl/command_line.h" -#include "lib/fxl/files/file.h" #include "lib/fxl/macros.h" #include "third_party/dart/runtime/include/dart_tools_api.h" namespace shell { -FlutterMain::FlutterMain(blink::Settings settings) - : settings_(std::move(settings)) {} - -FlutterMain::~FlutterMain() = default; - -static std::unique_ptr g_flutter_main; - -FlutterMain& FlutterMain::Get() { - FXL_CHECK(g_flutter_main) << "ensureInitializationComplete must have already " - "been called."; - return *g_flutter_main; -} - -const blink::Settings& FlutterMain::GetSettings() const { - return settings_; -} - -void FlutterMain::Init(JNIEnv* env, - jclass clazz, - jobject context, - jobjectArray jargs, - jstring bundlePath) { +static void Init(JNIEnv* env, + jclass clazz, + jobject context, + jobjectArray jargs, + jstring bundlePath) { + // Prepare command line arguments and initialize the shell. std::vector args; - args.push_back("flutter"); + args.push_back("flutter_tester"); for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) { args.push_back(std::move(arg)); } - auto command_line = fxl::CommandLineFromIterators(args.begin(), args.end()); - - auto settings = SettingsFromCommandLine(command_line); - - settings.assets_path = fml::jni::JavaStringToString(env, bundlePath); - - if (!blink::DartVM::IsRunningPrecompiledCode()) { - // Check to see if the appropriate kernel files are present and configure - // settings accordingly. - auto platform_kernel_path = - fml::paths::JoinPaths({settings.assets_path, "platform.dill"}); - auto application_kernel_path = - fml::paths::JoinPaths({settings.assets_path, "kernel_blob.bin"}); - - if (files::IsFile(platform_kernel_path) && - files::IsFile(application_kernel_path)) { - settings.kernel_snapshot_path = platform_kernel_path; - settings.application_kernel_asset = application_kernel_path; - } - } - settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { - fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); - }; - - settings.task_observer_remove = [](intptr_t key) { - fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); - }; - // Not thread safe. Will be removed when FlutterMain is refactored to no - // longer be a singleton. - g_flutter_main.reset(new FlutterMain(std::move(settings))); + auto command_line = fxl::CommandLineFromIterators(args.begin(), args.end()); + std::string icu_data_path = + command_line.GetOptionValueWithDefault("icu-data-file-path", ""); + Shell::InitStandalone(std::move(command_line), std::move(icu_data_path), + /* application_library_path= */ "", + fml::jni::JavaStringToString(env, bundlePath)); } static void RecordStartTimestamp(JNIEnv* env, @@ -91,7 +44,7 @@ static void RecordStartTimestamp(JNIEnv* env, blink::engine_main_enter_ts = Dart_TimelineGetMicros() - initTimeMicros; } -bool FlutterMain::Register(JNIEnv* env) { +bool RegisterFlutterMain(JNIEnv* env) { static const JNINativeMethod methods[] = { { .name = "nativeInit", diff --git a/shell/platform/android/flutter_main.h b/shell/platform/android/flutter_main.h index 6c8717e9cebdb..f4f65c499f966 100644 --- a/shell/platform/android/flutter_main.h +++ b/shell/platform/android/flutter_main.h @@ -7,34 +7,9 @@ #include -#include "flutter/common/settings.h" -#include "lib/fxl/macros.h" - namespace shell { -class FlutterMain { - public: - ~FlutterMain(); - - static bool Register(JNIEnv* env); - - static FlutterMain& Get(); - - const blink::Settings& GetSettings() const; - - private: - const blink::Settings settings_; - - FlutterMain(blink::Settings settings); - - static void Init(JNIEnv* env, - jclass clazz, - jobject context, - jobjectArray jargs, - jstring bundlePath); - - FXL_DISALLOW_COPY_AND_ASSIGN(FlutterMain); -}; +bool RegisterFlutterMain(JNIEnv* env); } // namespace shell diff --git a/shell/platform/android/library_loader.cc b/shell/platform/android/library_loader.cc index 569825ce33e21..c51d0114282f6 100644 --- a/shell/platform/android/library_loader.cc +++ b/shell/platform/android/library_loader.cc @@ -16,7 +16,7 @@ JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { bool result = false; // Register FlutterMain. - result = shell::FlutterMain::Register(env); + result = shell::RegisterFlutterMain(env); FXL_CHECK(result); // Register PlatformView diff --git a/shell/platform/android/platform_message_response_android.cc b/shell/platform/android/platform_message_response_android.cc deleted file mode 100644 index 214080ec5bde3..0000000000000 --- a/shell/platform/android/platform_message_response_android.cc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/shell/platform/android/platform_message_response_android.h" - -#include "flutter/shell/platform/android/platform_view_android_jni.h" -#include "lib/fxl/functional/make_copyable.h" - -namespace shell { - -PlatformMessageResponseAndroid::PlatformMessageResponseAndroid( - int response_id, - fml::jni::JavaObjectWeakGlobalRef weak_java_object, - fxl::RefPtr platform_task_runner) - : response_id_(response_id), - weak_java_object_(weak_java_object), - platform_task_runner_(std::move(platform_task_runner)) {} - -// |blink::PlatformMessageResponse| -void PlatformMessageResponseAndroid::Complete(std::vector data) { - platform_task_runner_->PostTask( - fxl::MakeCopyable([response = response_id_, // - weak_java_object = weak_java_object_, // - data = std::move(data) // - ]() { - // We are on the platform thread. Attempt to get the strong reference to - // the Java object. - auto env = fml::jni::AttachCurrentThread(); - auto java_object = weak_java_object.get(env); - - if (java_object.is_null()) { - // The Java object was collected before this message response got to - // it. Drop the response on the floor. - return; - } - - if (data.size() == 0) { - // If the data is empty, there is no reason to create a Java byte - // array. Make the response now with a nullptr now. - FlutterViewHandlePlatformMessageResponse(env, java_object.obj(), - response, nullptr); - } - - // Convert the vector to a Java byte array. - fml::jni::ScopedJavaLocalRef data_array( - env, env->NewByteArray(data.size())); - env->SetByteArrayRegion(data_array.obj(), 0, data.size(), - reinterpret_cast(data.data())); - - // Make the response call into Java. - FlutterViewHandlePlatformMessageResponse(env, java_object.obj(), - response, data_array.obj()); - })); -} - -// |blink::PlatformMessageResponse| -void PlatformMessageResponseAndroid::CompleteEmpty() { - Complete(std::vector{}); -} - -} // namespace shell diff --git a/shell/platform/android/platform_message_response_android.h b/shell/platform/android/platform_message_response_android.h deleted file mode 100644 index 2ee7f3336ac6d..0000000000000 --- a/shell/platform/android/platform_message_response_android.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2018 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_ANDROID_PLATFORM_MESSAGE_RESPONSE_ANDROID_H_ -#define FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_MESSAGE_RESPONSE_ANDROID_H_ - -#include "flutter/fml/platform/android/jni_weak_ref.h" -#include "flutter/fml/task_runner.h" -#include "flutter/lib/ui/window/platform_message_response.h" -#include "lib/fxl/macros.h" - -namespace shell { - -class PlatformMessageResponseAndroid : public blink::PlatformMessageResponse { - public: - // |blink::PlatformMessageResponse| - void Complete(std::vector data) override; - - // |blink::PlatformMessageResponse| - void CompleteEmpty() override; - - private: - PlatformMessageResponseAndroid( - int response_id, - fml::jni::JavaObjectWeakGlobalRef weak_java_object, - fxl::RefPtr platform_task_runner); - - int response_id_; - fml::jni::JavaObjectWeakGlobalRef weak_java_object_; - fxl::RefPtr platform_task_runner_; - - FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseAndroid); - FXL_DISALLOW_COPY_AND_ASSIGN(PlatformMessageResponseAndroid); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_PLATFORM_ANDROID_PLATFORM_MESSAGE_RESPONSE_ANDROID_H_ diff --git a/shell/platform/android/platform_view_android.cc b/shell/platform/android/platform_view_android.cc index 00d1e4b59e848..8f677045fb1f5 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -4,55 +4,288 @@ #include "flutter/shell/platform/android/platform_view_android.h" -#include +#include +#include +#include +#include + #include -#include "flutter/shell/common/io_manager.h" +#include "flutter/common/settings.h" +#include "flutter/common/threads.h" +#include "flutter/fml/platform/android/jni_util.h" +#include "flutter/fml/platform/android/scoped_java_ref.h" +#include "flutter/runtime/dart_service_isolate.h" +#include "flutter/shell/common/null_rasterizer.h" +#include "flutter/shell/gpu/gpu_rasterizer.h" #include "flutter/shell/platform/android/android_external_texture_gl.h" #include "flutter/shell/platform/android/android_surface_gl.h" -#include "flutter/shell/platform/android/platform_message_response_android.h" +#include "flutter/shell/platform/android/android_surface_software.h" +#include "flutter/shell/platform/android/apk_asset_provider.h" #include "flutter/shell/platform/android/platform_view_android_jni.h" #include "flutter/shell/platform/android/vsync_waiter_android.h" -#include "lib/fxl/synchronization/waitable_event.h" +#include "lib/fxl/functional/make_copyable.h" + +#if SHELL_ENABLE_VULKAN +#include "flutter/shell/platform/android/android_surface_vulkan.h" +#endif // SHELL_ENABLE_VULKAN namespace shell { -PlatformViewAndroid::PlatformViewAndroid( - PlatformView::Delegate& delegate, - blink::TaskRunners task_runners, - fml::jni::JavaObjectWeakGlobalRef java_object, - bool use_software_rendering) - : PlatformView(delegate, std::move(task_runners)), - java_object_(java_object), - android_surface_(AndroidSurface::Create(use_software_rendering)) { - FXL_CHECK(android_surface_) - << "Could not create an OpenGL, Vulkan or Software surface to setup " - "rendering."; +class PlatformMessageResponseAndroid : public blink::PlatformMessageResponse { + FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseAndroid); + + public: + void Complete(std::vector data) override { + fxl::RefPtr self(this); + blink::Threads::Platform()->PostTask( + fxl::MakeCopyable([ self, data = std::move(data) ]() mutable { + std::shared_ptr view = self->view_.lock(); + if (!view) + return; + static_cast(view.get()) + ->HandlePlatformMessageResponse(self->response_id_, + std::move(data)); + })); + } + + void CompleteEmpty() override { + fxl::RefPtr self(this); + blink::Threads::Platform()->PostTask(fxl::MakeCopyable([self]() mutable { + std::shared_ptr view = self->view_.lock(); + if (!view) + return; + static_cast(view.get()) + ->HandlePlatformMessageEmptyResponse(self->response_id_); + })); + } + + private: + PlatformMessageResponseAndroid(int response_id, + std::weak_ptr view) + : response_id_(response_id), view_(view) {} + + int response_id_; + std::weak_ptr view_; +}; + +static std::unique_ptr InitializePlatformSurfaceGL() { + const PlatformView::SurfaceConfig offscreen_config = { + .red_bits = 8, + .green_bits = 8, + .blue_bits = 8, + .alpha_bits = 8, + .depth_bits = 0, + .stencil_bits = 0, + }; + auto surface = std::make_unique(offscreen_config); + return surface->IsOffscreenContextValid() ? std::move(surface) : nullptr; +} + +static std::unique_ptr InitializePlatformSurfaceVulkan() { +#if SHELL_ENABLE_VULKAN + auto surface = std::make_unique(); + return surface->IsValid() ? std::move(surface) : nullptr; +#else // SHELL_ENABLE_VULKAN + return nullptr; +#endif // SHELL_ENABLE_VULKAN } +static std::unique_ptr InitializePlatformSurfaceSoftware() { + auto surface = std::make_unique(); + return surface->IsValid() ? std::move(surface) : nullptr; +} + +static std::unique_ptr InitializePlatformSurface() { + if (blink::Settings::Get().enable_software_rendering) { + if (auto surface = InitializePlatformSurfaceSoftware()) { + FXL_DLOG(INFO) << "Software surface initialized."; + return surface; + } + } + + if (auto surface = InitializePlatformSurfaceVulkan()) { + FXL_DLOG(INFO) << "Vulkan surface initialized."; + return surface; + } + + FXL_DLOG(INFO) + << "Could not initialize Vulkan surface. Falling back to OpenGL."; + + if (auto surface = InitializePlatformSurfaceGL()) { + FXL_DLOG(INFO) << "GL surface initialized."; + return surface; + } + + if (auto surface = InitializePlatformSurfaceSoftware()) { + FXL_DLOG(INFO) << "Software surface initialized."; + return surface; + } + + FXL_CHECK(false) + << "Could not initialize either the Vulkan, OpenGL, or Software" + "surface backends. Flutter requires a GPU to render."; + return nullptr; +} + +PlatformViewAndroid::PlatformViewAndroid() + : PlatformView(std::make_unique()), + android_surface_(InitializePlatformSurface()) {} + PlatformViewAndroid::~PlatformViewAndroid() = default; -void PlatformViewAndroid::NotifyCreated( - fxl::RefPtr native_window) { - InstallFirstFrameCallback(); - android_surface_->SetNativeWindow(native_window); - PlatformView::NotifyCreated(); +void PlatformViewAndroid::Attach() { + CreateEngine(); + + // Eagerly setup the IO thread context. We have already setup the surface. + SetupResourceContextOnIOThread(); + + UpdateThreadPriorities(); } -void PlatformViewAndroid::NotifyDestroyed() { - PlatformView::NotifyDestroyed(); - android_surface_->TeardownOnScreenContext(); +void PlatformViewAndroid::Detach() { + ReleaseSurface(); } -void PlatformViewAndroid::NotifyChanged(const SkISize& size) { - fxl::AutoResetWaitableEvent latch; - fml::TaskRunner::RunNowOrPostTask( - task_runners_.GetGPUTaskRunner(), // - [&latch, surface = android_surface_.get(), size]() { - surface->OnScreenSurfaceResize(size); - latch.Signal(); +void PlatformViewAndroid::SurfaceCreated(JNIEnv* env, + jobject jsurface, + jint backgroundColor) { + // Note: This frame ensures that any local references used by + // ANativeWindow_fromSurface are released immediately. This is needed as a + // workaround for https://code.google.com/p/android/issues/detail?id=68174 + fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env); + + // We have a drawing surface, so swap in a non-Null rasterizer. + SetRasterizer(std::make_unique(nullptr)); + + rasterizer_->AddNextFrameCallback([this]() { + JNIEnv* env = fml::jni::AttachCurrentThread(); + fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); + if (!view.is_null()) { + FlutterViewOnFirstFrame(env, view.obj()); + } + }); + + auto native_window = fxl::MakeRefCounted( + ANativeWindow_fromSurface(env, jsurface)); + + if (!native_window->IsValid()) { + return; + } + + if (!android_surface_->SetNativeWindow(native_window)) { + return; + } + + std::unique_ptr gpu_surface = android_surface_->CreateGPUSurface(); + + if (gpu_surface == nullptr || !gpu_surface->IsValid()) { + return; + } + + NotifyCreated(std::move(gpu_surface), [ + this, backgroundColor, native_window_size = native_window->GetSize() + ] { rasterizer().Clear(backgroundColor, native_window_size); }); +} + +void PlatformViewAndroid::SurfaceChanged(jint width, jint height) { + blink::Threads::Gpu()->PostTask([this, width, height]() { + if (android_surface_) { + android_surface_->OnScreenSurfaceResize(SkISize::Make(width, height)); + } + }); +} + +void PlatformViewAndroid::UpdateThreadPriorities() { + blink::Threads::Gpu()->PostTask( + []() { ::setpriority(PRIO_PROCESS, gettid(), -2); }); + + blink::Threads::UI()->PostTask( + []() { ::setpriority(PRIO_PROCESS, gettid(), -1); }); +} + +void PlatformViewAndroid::SurfaceDestroyed() { + ReleaseSurface(); +} + +void PlatformViewAndroid::RunBundleAndSnapshot(JNIEnv* env, std::string bundle_path, + std::string snapshot_override, + std::string entrypoint, + bool reuse_runtime_controller, + jobject assetManager) { + // TODO(jsimmons): remove snapshot_override from the public FlutterView API + FXL_CHECK(snapshot_override.empty()) << "snapshot_override is obsolete"; + + // The flutter assets directory name is the last directory of the bundle_path + // and the path into the APK + size_t last_slash_idx = bundle_path.rfind("/", bundle_path.size()); + std::string flutter_assets_dir = bundle_path.substr( + last_slash_idx + 1, bundle_path.size() - last_slash_idx); + + fxl::RefPtr asset_provider = + fxl::MakeRefCounted(env, assetManager, + flutter_assets_dir); + blink::Threads::UI()->PostTask( + [engine = engine_->GetWeakPtr(), + asset_provider = std::move(asset_provider), + bundle_path = std::move(bundle_path), entrypoint = std::move(entrypoint), + reuse_runtime_controller = reuse_runtime_controller] { + if (engine) + engine->RunBundleWithAssets( + std::move(asset_provider), std::move(bundle_path), + std::move(entrypoint), reuse_runtime_controller); }); - latch.Wait(); +} + +void PlatformViewAndroid::RunBundleAndSource(std::string bundle_path, + std::string main, + std::string packages) { + blink::Threads::UI()->PostTask([ + engine = engine_->GetWeakPtr(), bundle_path = std::move(bundle_path), + main = std::move(main), packages = std::move(packages) + ] { + if (engine) + engine->RunBundleAndSource(std::move(bundle_path), std::move(main), + std::move(packages)); + }); +} + +void PlatformViewAndroid::SetAssetBundlePathOnUI(std::string bundle_path) { + blink::Threads::UI()->PostTask( + [ engine = engine_->GetWeakPtr(), bundle_path = std::move(bundle_path) ] { + if (engine) + engine->SetAssetBundlePath(std::move(bundle_path)); + }); +} + +void PlatformViewAndroid::SetViewportMetrics(jfloat device_pixel_ratio, + jint physical_width, + jint physical_height, + jint physical_padding_top, + jint physical_padding_right, + jint physical_padding_bottom, + jint physical_padding_left, + jint physical_view_inset_top, + jint physical_view_inset_right, + jint physical_view_inset_bottom, + jint physical_view_inset_left) { + blink::ViewportMetrics metrics; + metrics.device_pixel_ratio = device_pixel_ratio; + metrics.physical_width = physical_width; + metrics.physical_height = physical_height; + metrics.physical_padding_top = physical_padding_top; + metrics.physical_padding_right = physical_padding_right; + metrics.physical_padding_bottom = physical_padding_bottom; + metrics.physical_padding_left = physical_padding_left; + metrics.physical_view_inset_top = physical_view_inset_top; + metrics.physical_view_inset_right = physical_view_inset_right; + metrics.physical_view_inset_bottom = physical_view_inset_bottom; + metrics.physical_view_inset_left = physical_view_inset_left; + + blink::Threads::UI()->PostTask([ engine = engine_->GetWeakPtr(), metrics ] { + if (engine) + engine->SetViewportMetrics(metrics); + }); } void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env, @@ -68,7 +301,7 @@ void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env, fxl::RefPtr response; if (response_id) { response = fxl::MakeRefCounted( - response_id, java_object_, task_runners_.GetPlatformTaskRunner()); + response_id, GetWeakPtr()); } PlatformView::DispatchPlatformMessage( @@ -82,7 +315,7 @@ void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env, fxl::RefPtr response; if (response_id) { response = fxl::MakeRefCounted( - response_id, java_object_, task_runners_.GetPlatformTaskRunner()); + response_id, GetWeakPtr()); } PlatformView::DispatchPlatformMessage( @@ -90,6 +323,20 @@ void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env, std::move(response))); } +void PlatformViewAndroid::DispatchPointerDataPacket(JNIEnv* env, + jobject buffer, + jint position) { + uint8_t* data = static_cast(env->GetDirectBufferAddress(buffer)); + + blink::Threads::UI()->PostTask(fxl::MakeCopyable([ + engine = engine_->GetWeakPtr(), + packet = std::make_unique(data, position) + ] { + if (engine.get()) + engine->DispatchPointerDataPacket(*packet); + })); +} + void PlatformViewAndroid::InvokePlatformMessageResponseCallback( JNIEnv* env, jint response_id, @@ -122,11 +369,10 @@ void PlatformViewAndroid::InvokePlatformMessageEmptyResponseCallback( message_response->CompleteEmpty(); } -// |shell::PlatformView| void PlatformViewAndroid::HandlePlatformMessage( fxl::RefPtr message) { JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef view = java_object_.get(env); + fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); if (view.is_null()) return; @@ -156,6 +402,35 @@ void PlatformViewAndroid::HandlePlatformMessage( } } +void PlatformViewAndroid::HandlePlatformMessageResponse( + int response_id, + std::vector data) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); + + if (view.is_null()) + return; + fml::jni::ScopedJavaLocalRef data_array( + env, env->NewByteArray(data.size())); + env->SetByteArrayRegion(data_array.obj(), 0, data.size(), + reinterpret_cast(data.data())); + + FlutterViewHandlePlatformMessageResponse(env, view.obj(), response_id, + data_array.obj()); +} + +void PlatformViewAndroid::HandlePlatformMessageEmptyResponse(int response_id) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + + fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); + + if (view.is_null()) + return; + FlutterViewHandlePlatformMessageResponse(env, view.obj(), response_id, + nullptr); +} + void PlatformViewAndroid::DispatchSemanticsAction(JNIEnv* env, jint id, jint action, @@ -176,14 +451,35 @@ void PlatformViewAndroid::DispatchSemanticsAction(JNIEnv* env, id, static_cast(action), std::move(args_vector)); } -// |shell::PlatformView| -void PlatformViewAndroid::UpdateSemantics(blink::SemanticsNodeUpdates update) { +void PlatformViewAndroid::SetSemanticsEnabled(jboolean enabled) { + PlatformView::SetSemanticsEnabled(enabled); +} + +void PlatformViewAndroid::ReleaseSurface() { + NotifyDestroyed(); + android_surface_->TeardownOnScreenContext(); + SetRasterizer(std::make_unique()); +} + +VsyncWaiter* PlatformViewAndroid::GetVsyncWaiter() { + if (!vsync_waiter_) + vsync_waiter_ = std::make_unique(); + return vsync_waiter_.get(); +} + +bool PlatformViewAndroid::ResourceContextMakeCurrent() { + FXL_CHECK(android_surface_); + return android_surface_->ResourceContextMakeCurrent(); +} + +void PlatformViewAndroid::UpdateSemantics( + blink::SemanticsNodeUpdates update) { constexpr size_t kBytesPerNode = 36 * sizeof(int32_t); constexpr size_t kBytesPerChild = sizeof(int32_t); JNIEnv* env = fml::jni::AttachCurrentThread(); { - fml::jni::ScopedJavaLocalRef view = java_object_.get(env); + fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); if (view.is_null()) return; @@ -264,6 +560,79 @@ void PlatformViewAndroid::UpdateSemantics(blink::SemanticsNodeUpdates update) { } } +void PlatformViewAndroid::RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + FXL_CHECK(env); + + { + fml::jni::ScopedJavaLocalRef local_flutter_view = + flutter_view_.get(env); + if (local_flutter_view.is_null()) { + // Collected. + return; + } + + // Grab the class of the flutter view. + jclass flutter_view_class = env->GetObjectClass(local_flutter_view.obj()); + FXL_CHECK(flutter_view_class); + + // Grab the runFromSource method id. + jmethodID run_from_source_method_id = env->GetMethodID( + flutter_view_class, "runFromSource", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + FXL_CHECK(run_from_source_method_id); + + // Invoke runFromSource on the Android UI thread. + jstring java_assets_directory = env->NewStringUTF(assets_directory.c_str()); + FXL_CHECK(java_assets_directory); + jstring java_main = env->NewStringUTF(main.c_str()); + FXL_CHECK(java_main); + jstring java_packages = env->NewStringUTF(packages.c_str()); + FXL_CHECK(java_packages); + env->CallVoidMethod(local_flutter_view.obj(), run_from_source_method_id, + java_assets_directory, java_main, java_packages); + } + + // Detaching from the VM deletes any stray local references. + fml::jni::DetachFromVM(); +} + +void PlatformViewAndroid::SetAssetBundlePath( + const std::string& assets_directory) { + JNIEnv* env = fml::jni::AttachCurrentThread(); + FXL_CHECK(env); + + { + fml::jni::ScopedJavaLocalRef local_flutter_view = + flutter_view_.get(env); + if (local_flutter_view.is_null()) { + // Collected. + return; + } + + // Grab the class of the flutter view. + jclass flutter_view_class = env->GetObjectClass(local_flutter_view.obj()); + FXL_CHECK(flutter_view_class); + + // Grab the setAssetBundlePath method id. + jmethodID method_id = env->GetMethodID( + flutter_view_class, "setAssetBundlePathOnUI", "(Ljava/lang/String;)V"); + FXL_CHECK(method_id); + + // Invoke setAssetBundlePath on the Android UI thread. + jstring java_assets_directory = env->NewStringUTF(assets_directory.c_str()); + FXL_CHECK(java_assets_directory); + + env->CallVoidMethod(local_flutter_view.obj(), method_id, + java_assets_directory); + } + + // Detaching from the VM deletes any stray local references. + fml::jni::DetachFromVM(); +} + void PlatformViewAndroid::RegisterExternalTexture( int64_t texture_id, const fml::jni::JavaObjectWeakGlobalRef& surface_texture) { @@ -271,56 +640,116 @@ void PlatformViewAndroid::RegisterExternalTexture( std::make_shared(texture_id, surface_texture)); } -// |shell::PlatformView| -std::unique_ptr PlatformViewAndroid::CreateVSyncWaiter() { - return std::make_unique(task_runners_); +void PlatformViewAndroid::MarkTextureFrameAvailable(int64_t texture_id) { + blink::Threads::Gpu()->PostTask([this, texture_id]() { + std::shared_ptr texture = + static_pointer_cast( + rasterizer_->GetTextureRegistry().GetTexture(texture_id)); + if (texture) { + texture->MarkNewFrameAvailable(); + } + }); + PlatformView::MarkTextureFrameAvailable(texture_id); } -// |shell::PlatformView| -std::unique_ptr PlatformViewAndroid::CreateRenderingSurface() { - return android_surface_->CreateGPUSurface(); -} +fml::jni::ScopedJavaLocalRef PlatformViewAndroid::GetBitmap( + JNIEnv* env) { + // Render the last frame to an array of pixels on the GPU thread. + // The pixels will be returned as a global JNI reference to an int array. + fxl::AutoResetWaitableEvent latch; + jobject pixels_ref = nullptr; + SkISize frame_size; + blink::Threads::Gpu()->PostTask([this, &latch, &pixels_ref, &frame_size]() { + GetBitmapGpuTask(&pixels_ref, &frame_size); + latch.Signal(); + }); -// |shell::PlatformView| -sk_sp PlatformViewAndroid::CreateResourceContext() const { - sk_sp resource_context; - if (android_surface_->ResourceContextMakeCurrent()) { - // TODO(chinmaygarde): Currently, this code depends on the fact that only - // the OpenGL surface will be able to make a resource context current. If - // this changes, this assumption breaks. Handle the same. - resource_context = IOManager::CreateCompatibleResourceLoadingContext( - GrBackend::kOpenGL_GrBackend); - } else { - FXL_DLOG(ERROR) << "Could not make the resource context current."; - } + latch.Wait(); - return resource_context; -} - -void PlatformViewAndroid::InstallFirstFrameCallback() { - // On Platform Task Runner. - SetNextFrameCallback( - [platform_view = GetWeakPtr(), - platform_task_runner = task_runners_.GetPlatformTaskRunner()]() { - // On GPU Task Runner. - platform_task_runner->PostTask([platform_view]() { - // Back on Platform Task Runner. - if (platform_view) { - reinterpret_cast(platform_view.get()) - ->FireFirstFrameCallback(); - } - }); - }); + // Convert the pixel array to an Android bitmap. + if (pixels_ref == nullptr) + return fml::jni::ScopedJavaLocalRef(); + + fml::jni::ScopedJavaGlobalRef pixels(env, pixels_ref); + + jclass bitmap_class = env->FindClass("android/graphics/Bitmap"); + FXL_CHECK(bitmap_class); + + jmethodID create_bitmap = env->GetStaticMethodID( + bitmap_class, "createBitmap", + "([IIILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); + FXL_CHECK(create_bitmap); + + jclass bitmap_config_class = env->FindClass("android/graphics/Bitmap$Config"); + FXL_CHECK(bitmap_config_class); + + jmethodID bitmap_config_value_of = env->GetStaticMethodID( + bitmap_config_class, "valueOf", + "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;"); + FXL_CHECK(bitmap_config_value_of); + + jstring argb = env->NewStringUTF("ARGB_8888"); + FXL_CHECK(argb); + + jobject bitmap_config = env->CallStaticObjectMethod( + bitmap_config_class, bitmap_config_value_of, argb); + FXL_CHECK(bitmap_config); + + jobject bitmap = env->CallStaticObjectMethod( + bitmap_class, create_bitmap, pixels.obj(), frame_size.width(), + frame_size.height(), bitmap_config); + + return fml::jni::ScopedJavaLocalRef(env, bitmap); } -void PlatformViewAndroid::FireFirstFrameCallback() { - JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef view = java_object_.get(env); - if (view.is_null()) { - // The Java object died. +void PlatformViewAndroid::GetBitmapGpuTask(jobject* pixels_out, + SkISize* size_out) { + flow::LayerTree* layer_tree = rasterizer_->GetLastLayerTree(); + if (layer_tree == nullptr) return; + + JNIEnv* env = fml::jni::AttachCurrentThread(); + FXL_CHECK(env); + + const SkISize& frame_size = layer_tree->frame_size(); + jsize pixels_size = frame_size.width() * frame_size.height(); + jintArray pixels_array = env->NewIntArray(pixels_size); + FXL_CHECK(pixels_array); + + jint* pixels = env->GetIntArrayElements(pixels_array, nullptr); + FXL_CHECK(pixels); + + SkImageInfo image_info = + SkImageInfo::Make(frame_size.width(), frame_size.height(), + kRGBA_8888_SkColorType, kPremul_SkAlphaType); + + sk_sp surface = SkSurface::MakeRasterDirect( + image_info, pixels, frame_size.width() * sizeof(jint)); + + flow::CompositorContext compositor_context(nullptr); + compositor_context.SetTextureRegistry(&texture_registry_); + SkCanvas* canvas = surface->getCanvas(); + flow::CompositorContext::ScopedFrame frame = + compositor_context.AcquireFrame(nullptr, canvas, false); + + canvas->clear(SK_ColorBLACK); + layer_tree->Raster(frame); + canvas->flush(); + + // Our configuration of Skia does not support rendering to the + // BitmapConfig.ARGB_8888 format expected by android.graphics.Bitmap. + // Convert from kRGBA_8888 to kBGRA_8888 (equivalent to ARGB_8888). + for (int i = 0; i < pixels_size; i++) { + uint8_t* bytes = reinterpret_cast(pixels + i); + std::swap(bytes[0], bytes[2]); } - FlutterViewOnFirstFrame(fml::jni::AttachCurrentThread(), view.obj()); + + env->ReleaseIntArrayElements(pixels_array, pixels, 0); + + *pixels_out = env->NewGlobalRef(pixels_array); + *size_out = frame_size; + + fml::jni::DetachFromVM(); } } // namespace shell diff --git a/shell/platform/android/platform_view_android.h b/shell/platform/android/platform_view_android.h index 9976c443f4248..4779ea16ab4a7 100644 --- a/shell/platform/android/platform_view_android.h +++ b/shell/platform/android/platform_view_android.h @@ -20,23 +20,45 @@ namespace shell { -class PlatformViewAndroid final : public PlatformView { +class PlatformViewAndroid : public PlatformView { public: static bool Register(JNIEnv* env); - PlatformViewAndroid(PlatformView::Delegate& delegate, - blink::TaskRunners task_runners, - fml::jni::JavaObjectWeakGlobalRef java_object, - bool use_software_rendering); + PlatformViewAndroid(); ~PlatformViewAndroid() override; - void NotifyCreated(fxl::RefPtr native_window); + virtual void Attach() override; - void NotifyChanged(const SkISize& size); + void Detach(); - // |shell::PlatformView| - void NotifyDestroyed() override; + void SurfaceCreated(JNIEnv* env, jobject jsurface, jint backgroundColor); + + void SurfaceChanged(jint width, jint height); + + void SurfaceDestroyed(); + + void RunBundleAndSnapshot(JNIEnv* env, std::string bundle_path, + std::string snapshot_override, + std::string entrypoint, + bool reuse_isolate, + jobject assetManager); + + void RunBundleAndSource(std::string bundle_path, + std::string main, + std::string packages); + + void SetViewportMetrics(jfloat device_pixel_ratio, + jint physical_width, + jint physical_height, + jint physical_padding_top, + jint physical_padding_right, + jint physical_padding_bottom, + jint physical_padding_left, + jint physical_view_inset_top, + jint physical_view_inset_right, + jint physical_view_inset_bottom, + jint physical_view_inset_left); void DispatchPlatformMessage(JNIEnv* env, std::string name, @@ -48,6 +70,8 @@ class PlatformViewAndroid final : public PlatformView { std::string name, jint response_id); + void DispatchPointerDataPacket(JNIEnv* env, jobject buffer, jint position); + void InvokePlatformMessageResponseCallback(JNIEnv* env, jint response_id, jobject java_response_data, @@ -62,37 +86,55 @@ class PlatformViewAndroid final : public PlatformView { jobject args, jint args_position); + void SetSemanticsEnabled(jboolean enabled); + + fml::jni::ScopedJavaLocalRef GetBitmap(JNIEnv* env); + + VsyncWaiter* GetVsyncWaiter() override; + + bool ResourceContextMakeCurrent() override; + + void UpdateSemantics(blink::SemanticsNodeUpdates update) override; + + void HandlePlatformMessage( + fxl::RefPtr message) override; + + void HandlePlatformMessageResponse(int response_id, + std::vector data); + + void HandlePlatformMessageEmptyResponse(int response_id); + + void RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) override; + + void SetAssetBundlePathOnUI(std::string bundle_path); + + void SetAssetBundlePath(const std::string& assets_directory) override; + void RegisterExternalTexture( int64_t texture_id, const fml::jni::JavaObjectWeakGlobalRef& surface_texture); + void MarkTextureFrameAvailable(int64_t texture_id) override; + + void set_flutter_view(const fml::jni::JavaObjectWeakGlobalRef& flutter_view) { + flutter_view_ = flutter_view; + } + private: - const fml::jni::JavaObjectWeakGlobalRef java_object_; - const std::unique_ptr android_surface_; + std::unique_ptr android_surface_; + fml::jni::JavaObjectWeakGlobalRef flutter_view_; // We use id 0 to mean that no response is expected. int next_response_id_ = 1; std::unordered_map> pending_responses_; - // |shell::PlatformView| - void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - - // |shell::PlatformView| - void HandlePlatformMessage( - fxl::RefPtr message) override; - - // |shell::PlatformView| - std::unique_ptr CreateVSyncWaiter() override; - - // |shell::PlatformView| - std::unique_ptr CreateRenderingSurface() override; - - // |shell::PlatformView| - sk_sp CreateResourceContext() const override; + void UpdateThreadPriorities(); - void InstallFirstFrameCallback(); + void ReleaseSurface(); - void FireFirstFrameCallback(); + void GetBitmapGpuTask(jobject* pixels_out, SkISize* size_out); FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewAndroid); }; diff --git a/shell/platform/android/platform_view_android_jni.cc b/shell/platform/android/platform_view_android_jni.cc index f75f54a896850..c819f3bfb5e41 100644 --- a/shell/platform/android/platform_view_android_jni.cc +++ b/shell/platform/android/platform_view_android_jni.cc @@ -4,26 +4,17 @@ #include "flutter/shell/platform/android/platform_view_android_jni.h" -#include - -#include - -#include "flutter/assets/directory_asset_bundle.h" #include "flutter/common/settings.h" -#include "flutter/fml/file.h" #include "flutter/fml/platform/android/jni_util.h" #include "flutter/fml/platform/android/jni_weak_ref.h" #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/runtime/dart_service_isolate.h" -#include "flutter/shell/common/run_configuration.h" #include "flutter/shell/platform/android/android_external_texture_gl.h" -#include "flutter/shell/platform/android/android_shell_holder.h" -#include "flutter/shell/platform/android/apk_asset_provider.h" -#include "flutter/shell/platform/android/flutter_main.h" #include "lib/fxl/arraysize.h" +#include "lib/fxl/logging.h" -#define ANDROID_SHELL_HOLDER \ - (reinterpret_cast(shell_holder)) +#define PLATFORM_VIEW \ + (*reinterpret_cast*>(platform_view)) namespace shell { @@ -87,12 +78,14 @@ void FlutterViewOnFirstFrame(JNIEnv* env, jobject obj) { static jmethodID g_attach_to_gl_context_method = nullptr; void SurfaceTextureAttachToGLContext(JNIEnv* env, jobject obj, jint textureId) { + ASSERT_IS_GPU_THREAD; env->CallVoidMethod(obj, g_attach_to_gl_context_method, textureId); FXL_CHECK(CheckException(env)); } static jmethodID g_update_tex_image_method = nullptr; void SurfaceTextureUpdateTexImage(JNIEnv* env, jobject obj) { + ASSERT_IS_GPU_THREAD; env->CallVoidMethod(obj, g_update_tex_image_method); FXL_CHECK(CheckException(env)); } @@ -101,12 +94,14 @@ static jmethodID g_get_transform_matrix_method = nullptr; void SurfaceTextureGetTransformMatrix(JNIEnv* env, jobject obj, jfloatArray result) { + ASSERT_IS_GPU_THREAD; env->CallVoidMethod(obj, g_get_transform_matrix_method, result); FXL_CHECK(CheckException(env)); } static jmethodID g_detach_from_gl_context_method = nullptr; void SurfaceTextureDetachFromGLContext(JNIEnv* env, jobject obj) { + ASSERT_IS_GPU_THREAD; env->CallVoidMethod(obj, g_detach_from_gl_context_method); FXL_CHECK(CheckException(env)); } @@ -114,22 +109,22 @@ void SurfaceTextureDetachFromGLContext(JNIEnv* env, jobject obj) { // Called By Java static jlong Attach(JNIEnv* env, jclass clazz, jobject flutterView) { - fml::jni::JavaObjectWeakGlobalRef java_object(env, flutterView); - auto shell_holder = std::make_unique( - FlutterMain::Get().GetSettings(), java_object); - if (shell_holder->IsValid()) { - return reinterpret_cast(shell_holder.release()); - } else { - return 0; - } + auto view = new PlatformViewAndroid(); + auto storage = new std::shared_ptr(view); + // Create a weak reference to the flutterView Java object so that we can make + // calls into it later. + view->Attach(); + view->set_flutter_view(fml::jni::JavaObjectWeakGlobalRef(env, flutterView)); + return reinterpret_cast(storage); } -static void Detach(JNIEnv* env, jobject jcaller, jlong shell_holder) { - // Nothing to do. +static void Detach(JNIEnv* env, jobject jcaller, jlong platform_view) { + PLATFORM_VIEW->Detach(); } -static void Destroy(JNIEnv* env, jobject jcaller, jlong shell_holder) { - delete ANDROID_SHELL_HOLDER; +static void Destroy(JNIEnv* env, jobject jcaller, jlong platform_view) { + PLATFORM_VIEW->Detach(); + delete &PLATFORM_VIEW; } static jstring GetObservatoryUri(JNIEnv* env, jclass clazz) { @@ -139,180 +134,67 @@ static jstring GetObservatoryUri(JNIEnv* env, jclass clazz) { static void SurfaceCreated(JNIEnv* env, jobject jcaller, - jlong shell_holder, - jobject jsurface, + jlong platform_view, + jobject surface, jint backgroundColor) { - // Note: This frame ensures that any local references used by - // ANativeWindow_fromSurface are released immediately. This is needed as a - // workaround for https://code.google.com/p/android/issues/detail?id=68174 - fml::jni::ScopedJavaLocalFrame scoped_local_reference_frame(env); - auto window = fxl::MakeRefCounted( - ANativeWindow_fromSurface(env, jsurface)); - ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyCreated(std::move(window)); + return PLATFORM_VIEW->SurfaceCreated(env, surface, backgroundColor); } static void SurfaceChanged(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jint width, jint height) { - ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyChanged( - SkISize::Make(width, height)); -} - -static void SurfaceDestroyed(JNIEnv* env, jobject jcaller, jlong shell_holder) { - ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyDestroyed(); -} - -std::unique_ptr CreateIsolateConfiguration( - const blink::AssetManager& asset_manager) { - if (blink::DartVM::IsRunningPrecompiledCode()) { - return IsolateConfiguration::CreateForPrecompiledCode(); - } - - const auto configuration_from_blob = - [&asset_manager](const std::string& snapshot_name) - -> std::unique_ptr { - std::vector blob; - if (asset_manager.GetAsBuffer(snapshot_name, &blob)) { - return IsolateConfiguration::CreateForSnapshot( - std::make_unique(std::move(blob))); - } - return nullptr; - }; - - if (auto kernel = configuration_from_blob("kernel_blob.bin")) { - return kernel; - } - - if (auto script = configuration_from_blob("snapshot_blob.bin")) { - return script; - } - - return nullptr; -} - -static void RunBundleAndSnapshot( - JNIEnv* env, - jobject jcaller, - jlong shell_holder, - jstring jbundlepath, - jstring /* snapshot override (unused) */, - jstring jEntrypoint, - jboolean /* reuse runtime controller (unused) */, - jobject jAssetManager) { - auto asset_manager = fxl::MakeRefCounted(); - - const auto bundlepath = fml::jni::JavaStringToString(env, jbundlepath); - - if (bundlepath.size() > 0) { - // If we got a bundle path, attempt to use that as a directory asset - // bundle. - asset_manager->PushBack(std::make_unique( - fml::OpenFile(bundlepath.c_str(), fml::OpenPermission::kRead, true))); - - // Use the last path component of the bundle path to determine the - // directory in the APK assets. - const auto last_slash_index = bundlepath.rfind("/", bundlepath.size()); - if (last_slash_index != std::string::npos) { - auto apk_asset_dir = bundlepath.substr( - last_slash_index + 1, bundlepath.size() - last_slash_index); - - asset_manager->PushBack(std::make_unique( - env, // jni environment - jAssetManager, // asset manager - std::move(apk_asset_dir)) // apk asset dir - ); - } - } - - auto isolate_configuration = CreateIsolateConfiguration(*asset_manager); - - if (!isolate_configuration) { - FXL_DLOG(ERROR) - << "Isolate configuration could not be determined for engine launch."; - return; - } - - RunConfiguration config(std::move(isolate_configuration), - std::move(asset_manager)); - - { - auto entrypoint = fml::jni::JavaStringToString(env, jEntrypoint); - if (entrypoint.size() > 0) { - config.SetEntrypoint(std::move(entrypoint)); - } - } - - ANDROID_SHELL_HOLDER->Launch(std::move(config)); + return PLATFORM_VIEW->SurfaceChanged(width, height); +} + +static void SurfaceDestroyed(JNIEnv* env, + jobject jcaller, + jlong platform_view) { + return PLATFORM_VIEW->SurfaceDestroyed(); +} + +static void RunBundleAndSnapshot(JNIEnv* env, + jobject jcaller, + jlong platform_view, + jstring bundlePath, + jstring snapshotOverride, + jstring entrypoint, + jboolean reuse_runtime_controller, + jobject assetManager) { + return PLATFORM_VIEW->RunBundleAndSnapshot( + env, + fml::jni::JavaStringToString(env, bundlePath), // + fml::jni::JavaStringToString(env, snapshotOverride), // + fml::jni::JavaStringToString(env, entrypoint), // + reuse_runtime_controller, // + assetManager + ); } -static void RunBundleAndSource(JNIEnv* env, - jobject jcaller, - jlong shell_holder, - jstring jBundlePath, - jstring main, - jstring packages) { - auto asset_manager = fxl::MakeRefCounted(); - - const auto bundlepath = fml::jni::JavaStringToString(env, jBundlePath); - - if (bundlepath.size() > 0) { - auto directory = - fml::OpenFile(bundlepath.c_str(), fml::OpenPermission::kRead, true); - asset_manager->PushBack( - std::make_unique(std::move(directory))); - } - - auto main_file_path = fml::jni::JavaStringToString(env, main); - auto packages_file_path = fml::jni::JavaStringToString(env, packages); - - auto config = - IsolateConfiguration::CreateForSource(main_file_path, packages_file_path); - - if (!config) { - return; - } - - RunConfiguration run_configuration(std::move(config), - std::move(asset_manager)); - - ANDROID_SHELL_HOLDER->Launch(std::move(run_configuration)); +void RunBundleAndSource(JNIEnv* env, + jobject jcaller, + jlong platform_view, + jstring bundlePath, + jstring main, + jstring packages) { + return PLATFORM_VIEW->RunBundleAndSource( + fml::jni::JavaStringToString(env, bundlePath), + fml::jni::JavaStringToString(env, main), + fml::jni::JavaStringToString(env, packages)); } void SetAssetBundlePathOnUI(JNIEnv* env, jobject jcaller, - jlong shell_holder, - jstring jBundlePath) { - const auto bundlepath = fml::jni::JavaStringToString(env, jBundlePath); - - if (bundlepath.size() == 0) { - return; - } - - auto directory = - fml::OpenFile(bundlepath.c_str(), fml::OpenPermission::kRead, true); - - if (!directory.is_valid()) { - return; - } - - std::unique_ptr directory_asset_bundle = - std::make_unique(std::move(directory)); - - if (!directory_asset_bundle->IsValid()) { - return; - } - - auto asset_manager = fxl::MakeRefCounted(); - asset_manager->PushBack(std::move(directory_asset_bundle)); - - ANDROID_SHELL_HOLDER->UpdateAssetManager(std::move(asset_manager)); + jlong platform_view, + jstring bundlePath) { + return PLATFORM_VIEW->SetAssetBundlePathOnUI( + fml::jni::JavaStringToString(env, bundlePath)); } static void SetViewportMetrics(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jfloat devicePixelRatio, jint physicalWidth, jint physicalHeight, @@ -324,194 +206,115 @@ static void SetViewportMetrics(JNIEnv* env, jint physicalViewInsetRight, jint physicalViewInsetBottom, jint physicalViewInsetLeft) { - const blink::ViewportMetrics metrics = { - .device_pixel_ratio = devicePixelRatio, - .physical_width = physicalWidth, - .physical_height = physicalHeight, - .physical_padding_top = physicalPaddingTop, - .physical_padding_right = physicalPaddingRight, - .physical_padding_bottom = physicalPaddingBottom, - .physical_padding_left = physicalPaddingLeft, - .physical_view_inset_top = physicalViewInsetTop, - .physical_view_inset_right = physicalViewInsetRight, - .physical_view_inset_bottom = physicalViewInsetBottom, - .physical_view_inset_left = physicalViewInsetLeft, - }; - - ANDROID_SHELL_HOLDER->SetViewportMetrics(metrics); + return PLATFORM_VIEW->SetViewportMetrics(devicePixelRatio, // + physicalWidth, // + physicalHeight, // + physicalPaddingTop, // + physicalPaddingRight, // + physicalPaddingBottom, // + physicalPaddingLeft, // + physicalViewInsetTop, // + physicalViewInsetRight, // + physicalViewInsetBottom, // + physicalViewInsetLeft); } -static jobject GetBitmap(JNIEnv* env, jobject jcaller, jlong shell_holder) { - auto screenshot = ANDROID_SHELL_HOLDER->Screenshot( - Rasterizer::ScreenshotType::UncompressedImage, false); - if (screenshot.data == nullptr) { - return nullptr; - } - - const SkISize& frame_size = screenshot.frame_size; - jsize pixels_size = frame_size.width() * frame_size.height(); - jintArray pixels_array = env->NewIntArray(pixels_size); - FXL_CHECK(pixels_array); - - jint* pixels = env->GetIntArrayElements(pixels_array, nullptr); - FXL_CHECK(pixels); - - auto pixels_src = static_cast(screenshot.data->data()); - - // Our configuration of Skia does not support rendering to the - // BitmapConfig.ARGB_8888 format expected by android.graphics.Bitmap. - // Convert from kRGBA_8888 to kBGRA_8888 (equivalent to ARGB_8888). - for (int i = 0; i < pixels_size; i++) { - int32_t src_pixel = pixels_src[i]; - uint8_t* src_bytes = reinterpret_cast(&src_pixel); - std::swap(src_bytes[0], src_bytes[2]); - pixels[i] = src_pixel; - } - - env->ReleaseIntArrayElements(pixels_array, pixels, 0); - - jclass bitmap_class = env->FindClass("android/graphics/Bitmap"); - FXL_CHECK(bitmap_class); - - jmethodID create_bitmap = env->GetStaticMethodID( - bitmap_class, "createBitmap", - "([IIILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;"); - FXL_CHECK(create_bitmap); - - jclass bitmap_config_class = env->FindClass("android/graphics/Bitmap$Config"); - FXL_CHECK(bitmap_config_class); - - jmethodID bitmap_config_value_of = env->GetStaticMethodID( - bitmap_config_class, "valueOf", - "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;"); - FXL_CHECK(bitmap_config_value_of); - - jstring argb = env->NewStringUTF("ARGB_8888"); - FXL_CHECK(argb); - - jobject bitmap_config = env->CallStaticObjectMethod( - bitmap_config_class, bitmap_config_value_of, argb); - FXL_CHECK(bitmap_config); - - return env->CallStaticObjectMethod(bitmap_class, create_bitmap, pixels_array, - frame_size.width(), frame_size.height(), - bitmap_config); +static jobject GetBitmap(JNIEnv* env, jobject jcaller, jlong platform_view) { + return PLATFORM_VIEW->GetBitmap(env).Release(); } static void DispatchPlatformMessage(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jstring channel, jobject message, jint position, jint responseId) { - ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchPlatformMessage( - env, // - fml::jni::JavaStringToString(env, channel), // - message, // - position, // - responseId // - ); + return PLATFORM_VIEW->DispatchPlatformMessage( + env, fml::jni::JavaStringToString(env, channel), message, position, + responseId); } static void DispatchEmptyPlatformMessage(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jstring channel, jint responseId) { - ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchEmptyPlatformMessage( - env, // - fml::jni::JavaStringToString(env, channel), // - responseId // - ); + return PLATFORM_VIEW->DispatchEmptyPlatformMessage( + env, fml::jni::JavaStringToString(env, channel), responseId); } static void DispatchPointerDataPacket(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jobject buffer, jint position) { - uint8_t* data = static_cast(env->GetDirectBufferAddress(buffer)); - auto packet = std::make_unique(data, position); - ANDROID_SHELL_HOLDER->DispatchPointerDataPacket(std::move(packet)); + return PLATFORM_VIEW->DispatchPointerDataPacket(env, buffer, position); } static void DispatchSemanticsAction(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jint id, jint action, jobject args, jint args_position) { - ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchSemanticsAction( - env, // - id, // - action, // - args, // - args_position // - ); + return PLATFORM_VIEW->DispatchSemanticsAction(env, id, action, args, + args_position); } static void SetSemanticsEnabled(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jboolean enabled) { - ANDROID_SHELL_HOLDER->GetPlatformView()->SetSemanticsEnabled(enabled); + return PLATFORM_VIEW->SetSemanticsEnabled(enabled); } static jboolean GetIsSoftwareRendering(JNIEnv* env, jobject jcaller) { - return FlutterMain::Get().GetSettings().enable_software_rendering; + return blink::Settings::Get().enable_software_rendering; } static void RegisterTexture(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jlong texture_id, jobject surface_texture) { - ANDROID_SHELL_HOLDER->GetPlatformView()->RegisterExternalTexture( - static_cast(texture_id), // - fml::jni::JavaObjectWeakGlobalRef(env, surface_texture) // - ); + PLATFORM_VIEW->RegisterExternalTexture( + static_cast(texture_id), + fml::jni::JavaObjectWeakGlobalRef(env, surface_texture)); } static void MarkTextureFrameAvailable(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jlong texture_id) { - ANDROID_SHELL_HOLDER->GetPlatformView()->MarkTextureFrameAvailable( + return PLATFORM_VIEW->MarkTextureFrameAvailable( static_cast(texture_id)); } static void UnregisterTexture(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jlong texture_id) { - ANDROID_SHELL_HOLDER->GetPlatformView()->UnregisterTexture( - static_cast(texture_id)); + PLATFORM_VIEW->UnregisterTexture(static_cast(texture_id)); } static void InvokePlatformMessageResponseCallback(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jint responseId, jobject message, jint position) { - ANDROID_SHELL_HOLDER->GetPlatformView() - ->InvokePlatformMessageResponseCallback(env, // - responseId, // - message, // - position // - ); + return PLATFORM_VIEW->InvokePlatformMessageResponseCallback( + env, responseId, message, position); } static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env, jobject jcaller, - jlong shell_holder, + jlong platform_view, jint responseId) { - ANDROID_SHELL_HOLDER->GetPlatformView() - ->InvokePlatformMessageEmptyResponseCallback(env, // - responseId // - ); + return PLATFORM_VIEW->InvokePlatformMessageEmptyResponseCallback(env, + responseId); } bool PlatformViewAndroid::Register(JNIEnv* env) { @@ -550,8 +353,8 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { }, { .name = "nativeRunBundleAndSnapshot", - .signature = "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/" - "String;ZLandroid/content/res/AssetManager;)V", + .signature = + "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;ZLandroid/content/res/AssetManager;)V", .fnPtr = reinterpret_cast(&shell::RunBundleAndSnapshot), }, { @@ -570,6 +373,11 @@ bool PlatformViewAndroid::Register(JNIEnv* env) { .signature = "(J)V", .fnPtr = reinterpret_cast(&shell::Detach), }, + { + .name = "nativeDestroy", + .signature = "(J)V", + .fnPtr = reinterpret_cast(&shell::Destroy), + }, { .name = "nativeGetObservatoryUri", .signature = "()Ljava/lang/String;", diff --git a/shell/platform/android/vsync_waiter_android.cc b/shell/platform/android/vsync_waiter_android.cc index 052de023b9a12..29e1958dcc011 100644 --- a/shell/platform/android/vsync_waiter_android.cc +++ b/shell/platform/android/vsync_waiter_android.cc @@ -7,7 +7,7 @@ #include #include -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/fml/platform/android/jni_util.h" #include "flutter/fml/platform/android/scoped_java_ref.h" #include "flutter/fml/trace_event.h" @@ -16,49 +16,68 @@ namespace shell { -static jlong CreatePendingCallback(VsyncWaiter::Callback callback); - -static void ConsumePendingCallback(jlong java_baton, - fxl::TimePoint frame_start_time, - fxl::TimePoint frame_target_time); - static fml::jni::ScopedJavaGlobalRef* g_vsync_waiter_class = nullptr; static jmethodID g_async_wait_for_vsync_method_ = nullptr; -VsyncWaiterAndroid::VsyncWaiterAndroid(blink::TaskRunners task_runners) - : VsyncWaiter(std::move(task_runners)) {} +VsyncWaiterAndroid::VsyncWaiterAndroid() : weak_factory_(this) {} VsyncWaiterAndroid::~VsyncWaiterAndroid() = default; -// |shell::VsyncWaiter| -void VsyncWaiterAndroid::AwaitVSync() { - auto java_baton = - CreatePendingCallback(std::bind(&VsyncWaiterAndroid::FireCallback, // - this, // - std::placeholders::_1, // - std::placeholders::_2 // - )); +void VsyncWaiterAndroid::AsyncWaitForVsync(Callback callback) { + FXL_DCHECK(!callback_); + callback_ = std::move(callback); + fml::WeakPtr* weak = + new fml::WeakPtr(); + *weak = weak_factory_.GetWeakPtr(); - task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() { + blink::Threads::Platform()->PostTask([weak] { JNIEnv* env = fml::jni::AttachCurrentThread(); - env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), // - g_async_wait_for_vsync_method_, // - java_baton // - ); + env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), + g_async_wait_for_vsync_method_, + reinterpret_cast(weak)); }); } +void VsyncWaiterAndroid::OnVsync(int64_t frameTimeNanos, + int64_t frameTargetTimeNanos) { + Callback callback = std::move(callback_); + callback_ = Callback(); + blink::Threads::UI()->PostTask( + [callback, frameTimeNanos, frameTargetTimeNanos] { + callback(fxl::TimePoint::FromEpochDelta( + fxl::TimeDelta::FromNanoseconds(frameTimeNanos)), + fxl::TimePoint::FromEpochDelta( + fxl::TimeDelta::FromNanoseconds(frameTargetTimeNanos))); + }); +} + static void OnNativeVsync(JNIEnv* env, jclass jcaller, jlong frameTimeNanos, jlong frameTargetTimeNanos, - jlong java_baton) { - auto frame_time = fxl::TimePoint::FromEpochDelta( - fxl::TimeDelta::FromNanoseconds(frameTimeNanos)); - auto target_time = fxl::TimePoint::FromEpochDelta( - fxl::TimeDelta::FromNanoseconds(frameTargetTimeNanos)); - - ConsumePendingCallback(java_baton, frame_time, target_time); + jlong cookie) { + // Note: The tag name must be "VSYNC" (it is special) so that the "Highlight + // Vsync" checkbox in the timeline can be enabled. + // See: https://github.com/catapult-project/catapult/blob/2091404475cbba9b786 + // 442979b6ec631305275a6/tracing/tracing/extras/vsync/vsync_auditor.html#L26 +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE + TRACE_EVENT1("flutter", "VSYNC", "mode", "basic"); +#else + { + constexpr size_t num_chars = sizeof(jlong) * CHAR_BIT * 3.4 + 2; + char deadline[num_chars]; + sprintf(deadline, "%lld", frameTargetTimeNanos / 1000); // microseconds + TRACE_EVENT2("flutter", "VSYNC", "mode", "basic", "deadline", deadline); + } +#endif + fml::WeakPtr* weak = + reinterpret_cast*>(cookie); + VsyncWaiterAndroid* waiter = weak->get(); + delete weak; + if (waiter) { + waiter->OnVsync(static_cast(frameTimeNanos), + static_cast(frameTargetTimeNanos)); + } } bool VsyncWaiterAndroid::Register(JNIEnv* env) { @@ -86,27 +105,4 @@ bool VsyncWaiterAndroid::Register(JNIEnv* env) { return env->RegisterNatives(clazz, methods, arraysize(methods)) == 0; } -struct PendingCallbackData { - VsyncWaiter::Callback callback; - - PendingCallbackData(VsyncWaiter::Callback p_callback) - : callback(std::move(p_callback)) { - FXL_DCHECK(callback); - } -}; - -static jlong CreatePendingCallback(VsyncWaiter::Callback callback) { - // This delete for this new is balanced in the consume call. - auto data = new PendingCallbackData(std::move(callback)); - return reinterpret_cast(data); -} - -static void ConsumePendingCallback(jlong java_baton, - fxl::TimePoint frame_start_time, - fxl::TimePoint frame_target_time) { - auto data = reinterpret_cast(java_baton); - data->callback(frame_start_time, frame_target_time); - delete data; -} - } // namespace shell diff --git a/shell/platform/android/vsync_waiter_android.h b/shell/platform/android/vsync_waiter_android.h index fd72a0a21f563..c73af4bfca6f0 100644 --- a/shell/platform/android/vsync_waiter_android.h +++ b/shell/platform/android/vsync_waiter_android.h @@ -12,17 +12,22 @@ namespace shell { -class VsyncWaiterAndroid final : public VsyncWaiter { +class VsyncWaiterAndroid : public VsyncWaiter { public: + VsyncWaiterAndroid(); + + ~VsyncWaiterAndroid() override; + static bool Register(JNIEnv* env); - VsyncWaiterAndroid(blink::TaskRunners task_runners); + void AsyncWaitForVsync(Callback callback) override; - ~VsyncWaiterAndroid() override; + void OnVsync(int64_t frameTimeNanos, int64_t frameTargetTimeNanos); private: - // |shell::VsyncWaiter| - void AwaitVSync() override; + Callback callback_; + fml::WeakPtr self_; + fml::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterAndroid); }; diff --git a/shell/platform/darwin/BUILD.gn b/shell/platform/darwin/BUILD.gn index c6f7acd6be76a..c971c443bcc30 100644 --- a/shell/platform/darwin/BUILD.gn +++ b/shell/platform/darwin/BUILD.gn @@ -6,8 +6,11 @@ assert(is_mac || is_ios) group("darwin") { if (is_mac) { + deps = [ + "desktop:shell_standalone", + ] if (!is_fuchsia_host) { - deps = [ + deps += [ "desktop:shell_application_bundle", ] } @@ -42,12 +45,15 @@ source_set("flutter_channels") { "$flutter_root/runtime", "$flutter_root/shell/common", "$flutter_root/shell/gpu", + "$flutter_root/shell/testing", "$flutter_root/sky/engine/wtf", "//garnet/public/lib/fxl", "//third_party/skia", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] } executable("flutter_channels_unittests") { @@ -62,7 +68,7 @@ executable("flutter_channels_unittests") { deps = [ ":flutter_channels", - "$flutter_root/testing", "//third_party/dart/runtime:libdart_jit", + "$flutter_root/testing", ] } diff --git a/shell/platform/darwin/common/BUILD.gn b/shell/platform/darwin/common/BUILD.gn index a1023737973a7..e6fa86366b080 100644 --- a/shell/platform/darwin/common/BUILD.gn +++ b/shell/platform/darwin/common/BUILD.gn @@ -9,23 +9,28 @@ source_set("common") { sources = [ "buffer_conversions.h", "buffer_conversions.mm", - "command_line.h", - "command_line.mm", + "platform_mac.h", + "platform_mac.mm", + "process_info_mac.cc", + "process_info_mac.h", ] set_sources_assignment_filter(sources_assignment_filter) deps = [ + "//third_party/dart/runtime:dart_api", "$flutter_root/common", "$flutter_root/flow", "$flutter_root/fml", "$flutter_root/runtime", "$flutter_root/shell/common", "$flutter_root/shell/gpu", + "$flutter_root/shell/testing", "$flutter_root/sky/engine/wtf", "//garnet/public/lib/fxl", - "//third_party/dart/runtime:dart_api", "//third_party/skia", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] } diff --git a/shell/platform/darwin/common/command_line.h b/shell/platform/darwin/common/command_line.h deleted file mode 100644 index dfc995b90f378..0000000000000 --- a/shell/platform/darwin/common/command_line.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 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_DARWIN_COMMON_COMMAND_LINE_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_COMMAND_LINE_H_ - -#include "lib/fxl/command_line.h" -#include "lib/fxl/macros.h" - -namespace shell { - -fxl::CommandLine CommandLineFromNSProcessInfo(); - -} // namespace shell - -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_COMMAND_LINE_H_ diff --git a/shell/platform/darwin/common/command_line.mm b/shell/platform/darwin/common/command_line.mm deleted file mode 100644 index bf8d4cc9d40f4..0000000000000 --- a/shell/platform/darwin/common/command_line.mm +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/shell/platform/darwin/common/command_line.h" - -#import - -namespace shell { - -fxl::CommandLine CommandLineFromNSProcessInfo() { - std::vector args_vector; - - for (NSString* arg in [NSProcessInfo processInfo].arguments) { - args_vector.emplace_back(arg.UTF8String); - } - - return fxl::CommandLineFromIterators(args_vector.begin(), args_vector.end()); -} - -} // namespace shell diff --git a/shell/platform/darwin/common/platform_mac.h b/shell/platform/darwin/common/platform_mac.h new file mode 100644 index 0000000000000..1989b25f11c43 --- /dev/null +++ b/shell/platform/darwin/common/platform_mac.h @@ -0,0 +1,20 @@ +// Copyright 2015 The Chromium 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 SHELL_PLATFORM_MAC_PLATFORM_MAC_H_ +#define SHELL_PLATFORM_MAC_PLATFORM_MAC_H_ + +#include "flutter/shell/common/engine.h" + +namespace shell { + +void PlatformMacMain(std::string icu_data_path, + std::string application_library_path, + std::string bundle_path); + +bool AttemptLaunchFromCommandLineSwitches(Engine* engine); + +} // namespace shell + +#endif // SHELL_PLATFORM_MAC_PLATFORM_MAC_H_ diff --git a/shell/platform/darwin/common/platform_mac.mm b/shell/platform/darwin/common/platform_mac.mm new file mode 100644 index 0000000000000..5af35a430beef --- /dev/null +++ b/shell/platform/darwin/common/platform_mac.mm @@ -0,0 +1,160 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/darwin/common/platform_mac.h" + +#include + +#include "flutter/common/threads.h" +#include "flutter/fml/trace_event.h" +#include "flutter/runtime/start_up.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/switches.h" +#include "flutter/shell/common/tracing_controller.h" +#include "flutter/sky/engine/wtf/MakeUnique.h" +#include "lib/fxl/command_line.h" +#include "lib/fxl/strings/string_view.h" +#include "third_party/dart/runtime/include/dart_tools_api.h" + +namespace shell { + +static fxl::CommandLine InitializedCommandLine() { + std::vector args_vector; + + for (NSString* arg in [NSProcessInfo processInfo].arguments) { + args_vector.emplace_back(arg.UTF8String); + } + + return fxl::CommandLineFromIterators(args_vector.begin(), args_vector.end()); +} + +class EmbedderState { + public: + EmbedderState(std::string icu_data_path, + std::string application_library_path, + std::string bundle_path) { + blink::engine_main_enter_ts = Dart_TimelineGetMicros(); + FXL_DCHECK([NSThread isMainThread]) + << "Embedder initialization must occur on the main platform thread"; + + auto command_line = InitializedCommandLine(); + + // This is about as early as tracing of any kind can start. Add an instant + // marker that can be used as a reference for startup. + TRACE_EVENT_INSTANT0("flutter", "main"); + + shell::Shell::InitStandalone(std::move(command_line), icu_data_path, application_library_path, + bundle_path); + } + + ~EmbedderState() {} + + private: + FXL_DISALLOW_COPY_AND_ASSIGN(EmbedderState); +}; + +void PlatformMacMain(std::string icu_data_path, + std::string application_library_path, + std::string bundle_path) { + static std::unique_ptr g_embedder; + static std::once_flag once_main; + + std::call_once(once_main, [&]() { + g_embedder = + WTF::MakeUnique(icu_data_path, application_library_path, bundle_path); + }); +} + +static bool FlagsValidForCommandLineLaunch(const std::string& bundle_path, + const std::string& main, + const std::string& packages) { + if (main.empty() || packages.empty() || bundle_path.empty()) { + return false; + } + + // Ensure that the paths exists. This catches cases where the user has + // successfully launched the application from the tooling but has since moved + // the source files on disk and is launching again directly. + + NSFileManager* manager = [NSFileManager defaultManager]; + + if (![manager fileExistsAtPath:@(main.c_str())]) { + return false; + } + + if (![manager fileExistsAtPath:@(packages.c_str())]) { + return false; + } + + if (![manager fileExistsAtPath:@(bundle_path.c_str())]) { + return false; + } + + return true; +} + +static std::string ResolveCommandLineLaunchFlag(const fxl::StringView name) { + const auto& command_line = shell::Shell::Shared().GetCommandLine(); + + std::string command_line_option; + if (command_line.GetOptionValue(name, &command_line_option)) { + return command_line_option; + } + + const char* saved_default = + [[NSUserDefaults standardUserDefaults] stringForKey:@(name.data())].UTF8String; + + if (saved_default != NULL) { + return saved_default; + } + + return ""; +} + +bool AttemptLaunchFromCommandLineSwitches(Engine* engine) { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + + const auto& command_line = shell::Shell::Shared().GetCommandLine(); + + if (command_line.HasOption(FlagForSwitch(Switch::FlutterAssetsDir)) || + command_line.HasOption(FlagForSwitch(Switch::MainDartFile)) || + command_line.HasOption(FlagForSwitch(Switch::Packages))) { + // The main dart file, Flutter assets directory and the package root must be + // specified in one go. We dont want to end up in a situation where we take + // one value from the command line and the others from user defaults. In + // case, any new flags are specified, forget about all the old ones. + [defaults removeObjectForKey:@(FlagForSwitch(Switch::FlutterAssetsDir).data())]; + [defaults removeObjectForKey:@(FlagForSwitch(Switch::MainDartFile).data())]; + [defaults removeObjectForKey:@(FlagForSwitch(Switch::Packages).data())]; + + [defaults synchronize]; + } + + std::string bundle_path = ResolveCommandLineLaunchFlag(FlagForSwitch(Switch::FlutterAssetsDir)); + std::string main = ResolveCommandLineLaunchFlag(FlagForSwitch(Switch::MainDartFile)); + std::string packages = ResolveCommandLineLaunchFlag(FlagForSwitch(Switch::Packages)); + + if (!FlagsValidForCommandLineLaunch(bundle_path, main, packages)) { + return false; + } + + // Save the newly resolved dart main file and the package root to user + // defaults so that the next time the user launches the application in the + // simulator without the tooling, the application boots up. + [defaults setObject:@(bundle_path.c_str()) + forKey:@(FlagForSwitch(Switch::FlutterAssetsDir).data())]; + [defaults setObject:@(main.c_str()) forKey:@(FlagForSwitch(Switch::MainDartFile).data())]; + [defaults setObject:@(packages.c_str()) forKey:@(FlagForSwitch(Switch::Packages).data())]; + + [defaults synchronize]; + + blink::Threads::UI()->PostTask([ engine = engine->GetWeakPtr(), bundle_path, main, packages ] { + if (engine) + engine->RunBundleAndSource(bundle_path, main, packages); + }); + + return true; +} + +} // namespace shell diff --git a/shell/platform/darwin/common/process_info_mac.cc b/shell/platform/darwin/common/process_info_mac.cc new file mode 100644 index 0000000000000..11f70f305a3e9 --- /dev/null +++ b/shell/platform/darwin/common/process_info_mac.cc @@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/darwin/common/process_info_mac.h" + +namespace shell { + +ProcessInfoMac::ProcessInfoMac() = default; + +ProcessInfoMac::~ProcessInfoMac() = default; + +bool ProcessInfoMac::SampleNow() { + mach_msg_type_number_t size = MACH_TASK_BASIC_INFO_COUNT; + kern_return_t result = + task_info(mach_task_self(), // + MACH_TASK_BASIC_INFO, // + reinterpret_cast(&last_sample_), // + &size); + if (result == KERN_SUCCESS) { + return true; + } + + last_sample_ = {}; + return false; +} + +size_t ProcessInfoMac::GetVirtualMemorySize() { + return last_sample_.virtual_size; +} + +size_t ProcessInfoMac::GetResidentMemorySize() { + return last_sample_.resident_size; +} + +} // namespace shell diff --git a/shell/platform/darwin/common/process_info_mac.h b/shell/platform/darwin/common/process_info_mac.h new file mode 100644 index 0000000000000..7edc8034173e0 --- /dev/null +++ b/shell/platform/darwin/common/process_info_mac.h @@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium 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_DARWIN_COMMON_PROCESS_INFO_MAC_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_PROCESS_INFO_MAC_H_ + +#include +#include +#include +#include "flutter/flow/process_info.h" +#include "lib/fxl/macros.h" + +namespace shell { + +class ProcessInfoMac : public flow::ProcessInfo { + public: + ProcessInfoMac(); + + ~ProcessInfoMac(); + + bool SampleNow() override; + + size_t GetVirtualMemorySize() override; + + size_t GetResidentMemorySize() override; + + private: + struct mach_task_basic_info last_sample_; + + FXL_DISALLOW_COPY_AND_ASSIGN(ProcessInfoMac); +}; + +} // namespace shell + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_COMMON_PROCESS_INFO_MAC_H_ diff --git a/shell/platform/darwin/desktop/BUILD.gn b/shell/platform/darwin/desktop/BUILD.gn index 5ec3298be4aa4..a9c05f85ef284 100644 --- a/shell/platform/darwin/desktop/BUILD.gn +++ b/shell/platform/darwin/desktop/BUILD.gn @@ -8,8 +8,10 @@ source_set("mac_desktop_platform") { visibility = [ ":*" ] sources = [ - "flutter_application_delegate.h", - "flutter_application_delegate.mm", + "flutter_app_delegate.h", + "flutter_app_delegate.m", + "flutter_application.h", + "flutter_application.mm", "flutter_window.h", "flutter_window.mm", "main_mac.mm", @@ -20,22 +22,32 @@ source_set("mac_desktop_platform") { ] deps = [ + "//third_party/dart/runtime:libdart_jit", "$flutter_root/common", "$flutter_root/fml", "$flutter_root/shell/common", "$flutter_root/shell/gpu", "$flutter_root/shell/platform/darwin/common", + "$flutter_root/shell/testing", "$flutter_root/synchronization", "//garnet/public/lib/fxl", - "//third_party/dart/runtime:libdart_jit", "//third_party/skia", - "//third_party/skia:gpu", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] +} + +executable("shell_standalone") { + output_name = "flutter_tester" + deps = [ + ":mac_desktop_platform", + ] } if (!is_fuchsia_host) { + import("//build/config/mac/rules.gni") resource_copy_mac("mac_desktop_resources") { diff --git a/shell/platform/darwin/desktop/Info.plist b/shell/platform/darwin/desktop/Info.plist index 048afb6dadca2..31d3f1240db6b 100644 --- a/shell/platform/darwin/desktop/Info.plist +++ b/shell/platform/darwin/desktop/Info.plist @@ -9,11 +9,11 @@ CFBundleIconFile CFBundleIdentifier - io.flutter.engine + io.flutter CFBundleInfoDictionaryVersion 6.0 CFBundleName - Flutter Engine + Flutter CFBundlePackageType APPL CFBundleShortVersionString @@ -26,7 +26,9 @@ 10.6 NSHumanReadableCopyright Copyright 2015 The Flutter Authors. All rights reserved. + NSMainNibFile + flutter_mac NSPrincipalClass - NSApplication + FlutterApplication diff --git a/shell/platform/darwin/desktop/flutter_app_delegate.h b/shell/platform/darwin/desktop/flutter_app_delegate.h new file mode 100644 index 0000000000000..d6addcb17d0a4 --- /dev/null +++ b/shell/platform/darwin/desktop/flutter_app_delegate.h @@ -0,0 +1,14 @@ +// Copyright 2015 The Chromium 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 __SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APP_DELEGATE__ +#define __SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APP_DELEGATE__ + +#import + +@interface FlutterAppDelegate : NSObject + +@end + +#endif /* defined(__SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APP_DELEGATE__) */ diff --git a/shell/platform/darwin/desktop/flutter_app_delegate.m b/shell/platform/darwin/desktop/flutter_app_delegate.m new file mode 100644 index 0000000000000..7e2dfd68389f8 --- /dev/null +++ b/shell/platform/darwin/desktop/flutter_app_delegate.m @@ -0,0 +1,15 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "flutter_app_delegate.h" + +@interface FlutterAppDelegate () + +@property(assign) IBOutlet NSWindow* window; + +@end + +@implementation FlutterAppDelegate + +@end diff --git a/shell/platform/darwin/desktop/flutter_application_delegate.h b/shell/platform/darwin/desktop/flutter_application.h similarity index 65% rename from shell/platform/darwin/desktop/flutter_application_delegate.h rename to shell/platform/darwin/desktop/flutter_application.h index 3995557b25e79..6a4167b5f273a 100644 --- a/shell/platform/darwin/desktop/flutter_application_delegate.h +++ b/shell/platform/darwin/desktop/flutter_application.h @@ -1,14 +1,13 @@ -// Copyright 2017 The Flutter Authors. All rights reserved. +// Copyright 2015 The Chromium 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_DARWIN_DESKTOP_FLUTTER_APPLICATION_DELEGATE_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_DELEGATE_H_ +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_H_ #import -@interface FlutterApplicationDelegate : NSObject - +@interface FlutterApplication : NSApplication @end -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_DELEGATE_H_ +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_H_ diff --git a/shell/platform/darwin/desktop/flutter_application.mm b/shell/platform/darwin/desktop/flutter_application.mm new file mode 100644 index 0000000000000..57b1c83ba069a --- /dev/null +++ b/shell/platform/darwin/desktop/flutter_application.mm @@ -0,0 +1,8 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/darwin/desktop/flutter_application.h" + +@implementation FlutterApplication +@end diff --git a/shell/platform/darwin/desktop/flutter_application_delegate.mm b/shell/platform/darwin/desktop/flutter_application_delegate.mm deleted file mode 100644 index 03076b848b25f..0000000000000 --- a/shell/platform/darwin/desktop/flutter_application_delegate.mm +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/shell/platform/darwin/desktop/flutter_application_delegate.h" -#include "flutter/shell/platform/darwin/desktop/flutter_window.h" - -#include - -@implementation FlutterApplicationDelegate - -- (void)applicationWillFinishLaunching:(NSNotification*)notification { - [self configureMainMenuBar]; - [self onNewFlutterWindow:self]; -} - -- (void)configureMainMenuBar { - NSMenu* mainMenu = [[[NSMenu alloc] initWithTitle:@"MainMenu"] autorelease]; - - NSMenuItem* engineItem = - [[[NSMenuItem alloc] initWithTitle:@"Engine" action:NULL keyEquivalent:@""] autorelease]; - - NSMenu* engineMenu = [[[NSMenu alloc] initWithTitle:@"EngineMenu"] autorelease]; - - NSMenuItem* newEngineItem = [[[NSMenuItem alloc] initWithTitle:@"New Engine" - action:@selector(onNewFlutterWindow:) - keyEquivalent:@""] autorelease]; - newEngineItem.keyEquivalent = @"n"; - newEngineItem.keyEquivalentModifierMask = NSCommandKeyMask; - - NSMenuItem* shutdownEngineItem = - [[[NSMenuItem alloc] initWithTitle:@"Shutdown Engine" - action:@selector(onShutdownFlutterWindow:) - keyEquivalent:@""] autorelease]; - shutdownEngineItem.keyEquivalent = @"w"; - shutdownEngineItem.keyEquivalentModifierMask = NSCommandKeyMask; - - NSMenuItem* quitItem = [[[NSMenuItem alloc] initWithTitle:@"Quit" - action:@selector(onQuitFlutterApplication:) - keyEquivalent:@""] autorelease]; - quitItem.keyEquivalent = @"q"; - quitItem.keyEquivalentModifierMask = NSCommandKeyMask; - - [mainMenu addItem:engineItem]; - [engineItem setSubmenu:engineMenu]; - [engineMenu addItem:newEngineItem]; - [engineMenu addItem:shutdownEngineItem]; - [engineMenu addItem:quitItem]; - - [NSApplication sharedApplication].mainMenu = mainMenu; -} - -- (void)onNewFlutterWindow:(id)sender { - FlutterWindow* window = [[FlutterWindow alloc] init]; - [window setReleasedWhenClosed:YES]; - - NSWindow* currentKeyWindow = [NSApplication sharedApplication].keyWindow; - - if (currentKeyWindow == nil) { - [window center]; - } else { - [window center]; - NSPoint currentWindowFrameOrigin = window.frame.origin; - currentWindowFrameOrigin.x = currentKeyWindow.frame.origin.x + 20; - currentWindowFrameOrigin.y = currentKeyWindow.frame.origin.y - 20; - [window setFrameOrigin:currentWindowFrameOrigin]; - } - - [window makeKeyAndOrderFront:sender]; -} - -- (void)onShutdownFlutterWindow:(id)sender { - [[NSApplication sharedApplication].keyWindow close]; -} - -- (void)onQuitFlutterApplication:(id)sender { - exit(0); -} - -@end diff --git a/shell/platform/darwin/desktop/flutter_mac.xib b/shell/platform/darwin/desktop/flutter_mac.xib new file mode 100644 index 0000000000000..c02ab7912da5a --- /dev/null +++ b/shell/platform/darwin/desktop/flutter_mac.xib @@ -0,0 +1,695 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/shell/platform/darwin/desktop/flutter_window.h b/shell/platform/darwin/desktop/flutter_window.h index e07fe4eeb7520..851535ba38e9e 100644 --- a/shell/platform/darwin/desktop/flutter_window.h +++ b/shell/platform/darwin/desktop/flutter_window.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW_H_ -#define SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW_H_ +#ifndef __SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW__ +#define __SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW__ #import @@ -11,4 +11,4 @@ @end -#endif // SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW_H_ +#endif /* defined(__SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW__) */ diff --git a/shell/platform/darwin/desktop/flutter_window.mm b/shell/platform/darwin/desktop/flutter_window.mm index 4c87200fb3856..ca080e9275742 100644 --- a/shell/platform/darwin/desktop/flutter_window.mm +++ b/shell/platform/darwin/desktop/flutter_window.mm @@ -2,25 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #import "flutter_window.h" -#include - -#include "flutter/common/task_runners.h" -#include "flutter/fml/message_loop.h" -#include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/switches.h" -#include "flutter/shell/common/thread_host.h" +#include "flutter/common/threads.h" #include "flutter/shell/gpu/gpu_surface_gl.h" -#include "flutter/shell/platform/darwin/common/command_line.h" #include "flutter/shell/platform/darwin/desktop/platform_view_mac.h" -#include "lib/fxl/functional/make_copyable.h" -@interface FlutterWindow () +@interface FlutterWindow () -@property(strong) NSOpenGLView* renderSurface; +@property(assign) IBOutlet NSOpenGLView* renderSurface; +@property(getter=isSurfaceSetup) BOOL surfaceSetup; @end @@ -46,130 +37,34 @@ @interface FlutterWindow () } @implementation FlutterWindow { - shell::ThreadHost _thread_host; - std::unique_ptr _shell; + std::shared_ptr _platformView; bool _mouseIsDown; } -- (instancetype)init { - self = - [super initWithContentRect:NSMakeRect(10.0, 10.0, 800.0, 600.0) - styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask - backing:NSBackingStoreBuffered - defer:YES]; - if (self) { - self.delegate = self; - [self setupRenderSurface]; - [self setupShell]; - [self updateWindowSize]; - } - - return self; -} - -- (void)setupRenderSurface { - NSOpenGLView* renderSurface = [[[NSOpenGLView alloc] init] autorelease]; - const NSOpenGLPixelFormatAttribute attrs[] = { - NSOpenGLPFADoubleBuffer, // - NSOpenGLPFAAllowOfflineRenderers, // - 0 // - }; - renderSurface.pixelFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs] autorelease]; - renderSurface.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - renderSurface.frame = - NSMakeRect(0.0, 0.0, self.contentView.bounds.size.width, self.contentView.bounds.size.height); - [self.contentView addSubview:renderSurface]; - self.renderSurface = renderSurface; -} - -static std::string CreateThreadLabel() { - std::stringstream stream; - static int index = 1; - stream << "io.flutter." << index++; - return stream.str(); -} - -- (void)setupShell { - FXL_DCHECK(!_shell) << "The shell must not already be set."; +@synthesize renderSurface = _renderSurface; +@synthesize surfaceSetup = _surfaceSetup; - auto thread_label = CreateThreadLabel(); +- (void)awakeFromNib { + [super awakeFromNib]; - // Create the threads on which to run the shell. - _thread_host = {thread_label, shell::ThreadHost::Type::GPU | shell::ThreadHost::Type::UI | - shell::ThreadHost::Type::IO}; + self.delegate = self; - // Grab the task runners for the newly created threads. - fml::MessageLoop::EnsureInitializedForCurrentThread(); - blink::TaskRunners task_runners(thread_label, // label - fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform - _thread_host.gpu_thread->GetTaskRunner(), // GPU - _thread_host.ui_thread->GetTaskRunner(), // UI - _thread_host.io_thread->GetTaskRunner() // IO - ); - - // Figure out the settings from the command line arguments. - auto settings = shell::SettingsFromCommandLine(shell::CommandLineFromNSProcessInfo()); - - if (settings.icu_data_path.size() == 0) { - settings.icu_data_path = - [[NSBundle mainBundle] pathForResource:@"icudtl.dat" ofType:@""].UTF8String; - } - - settings.using_blink = false; - - settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { - fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); - }; - - settings.task_observer_remove = [](intptr_t key) { - fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); - }; - - // Setup the callback that will be run on the appropriate threads. - shell::Shell::CreateCallback on_create_platform_view = - [render_surface = self.renderSurface](shell::Shell& shell) { - return std::make_unique(shell, render_surface); - }; - - shell::Shell::CreateCallback on_create_rasterizer = [](shell::Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }; - - // Finally, create the shell. - _shell = shell::Shell::Create(std::move(task_runners), settings, on_create_platform_view, - on_create_rasterizer); - - // Launch the engine with the inferred run configuration. - _shell->GetTaskRunners().GetUITaskRunner()->PostTask(fxl::MakeCopyable( - [engine = _shell->GetEngine(), - config = shell::RunConfiguration::InferFromSettings(_shell->GetSettings())]() mutable { - if (engine) { - auto result = engine->Run(std::move(config)); - if (!result) { - FXL_LOG(ERROR) << "Could not launch the engine with configuration."; - } - } - })); - - [self notifySurfaceCreated]; + [self updateWindowSize]; } -- (void)notifySurfaceCreated { - if (!_shell || !_shell->IsSetup()) { - return; - } +- (void)setupPlatformView { + FXL_DCHECK(_platformView == nullptr) << "The platform view must not already be set."; - // Tell the platform view that it has a GL surface. - _shell->GetPlatformView()->NotifyCreated(); + _platformView = std::make_shared(self.renderSurface); + _platformView->Attach(); + _platformView->SetupResourceContextOnIOThread(); + _platformView->NotifyCreated(std::make_unique(_platformView.get())); } -- (void)notifySurfaceDestroyed { - if (!_shell || !_shell->IsSetup()) { - return; - } - - // Tell the platform view that its surface is about to be lost. - _shell->GetPlatformView()->NotifyDestroyed(); +// TODO(eseidel): This does not belong in flutter_window! +// Probably belongs in NSApplicationDelegate didFinishLaunching. +- (void)setupAndLoadDart { + _platformView->SetupAndLoadDart(); } - (void)windowDidResize:(NSNotification*)notification { @@ -177,28 +72,34 @@ - (void)windowDidResize:(NSNotification*)notification { } - (void)updateWindowSize { - if (!_shell) { - return; - } + [self setupSurfaceIfNecessary]; blink::ViewportMetrics metrics; auto size = self.renderSurface.frame.size; metrics.physical_width = size.width; metrics.physical_height = size.height; - _shell->GetTaskRunners().GetUITaskRunner()->PostTask([engine = _shell->GetEngine(), metrics]() { - if (engine) { + + blink::Threads::UI()->PostTask([ engine = _platformView->engine().GetWeakPtr(), metrics ] { + if (engine.get()) { engine->SetViewportMetrics(metrics); } }); } -#pragma mark - Responder overrides - -- (void)dispatchEvent:(NSEvent*)event phase:(NSEventPhase)phase { - if (!_shell) { +- (void)setupSurfaceIfNecessary { + if (self.isSurfaceSetup) { return; } + self.surfaceSetup = YES; + + [self setupPlatformView]; + [self setupAndLoadDart]; +} + +#pragma mark - Responder overrides + +- (void)dispatchEvent:(NSEvent*)event phase:(NSEventPhase)phase { NSPoint location = [_renderSurface convertPoint:event.locationInWindow fromView:nil]; location.y = _renderSurface.frame.size.height - location.y; @@ -233,14 +134,13 @@ - (void)dispatchEvent:(NSEvent*)event phase:(NSEventPhase)phase { break; } - _shell->GetTaskRunners().GetUITaskRunner()->PostTask( - [engine = _shell->GetEngine(), pointer_data] { - if (engine) { - blink::PointerDataPacket packet(1); - packet.SetPointerData(0, pointer_data); - engine->DispatchPointerDataPacket(packet); - } - }); + blink::Threads::UI()->PostTask([ engine = _platformView->engine().GetWeakPtr(), pointer_data ] { + if (engine.get()) { + blink::PointerDataPacket packet(1); + packet.SetPointerData(0, pointer_data); + engine->DispatchPointerDataPacket(packet); + } + }); } - (void)mouseDown:(NSEvent*)event { @@ -255,18 +155,11 @@ - (void)mouseUp:(NSEvent*)event { [self dispatchEvent:event phase:NSEventPhaseEnded]; } -- (void)reset { - [self notifySurfaceDestroyed]; - _shell.reset(); - _thread_host.Reset(); -} - -- (void)windowWillClose:(NSNotification*)notification { - [self reset]; -} - - (void)dealloc { - [self reset]; + if (_platformView) { + _platformView->NotifyDestroyed(); + } + [super dealloc]; } diff --git a/shell/platform/darwin/desktop/main_mac.mm b/shell/platform/darwin/desktop/main_mac.mm index edd08d0c8b783..808a5f63f1d14 100644 --- a/shell/platform/darwin/desktop/main_mac.mm +++ b/shell/platform/darwin/desktop/main_mac.mm @@ -7,20 +7,91 @@ #include #include "flutter/fml/message_loop.h" +#include "flutter/shell/common/platform_view.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/switches.h" -#include "flutter/shell/platform/darwin/desktop/flutter_application_delegate.h" +#include "flutter/shell/platform/darwin/common/platform_mac.h" +#include "flutter/shell/platform/darwin/desktop/flutter_application.h" +#include "flutter/shell/testing/test_runner.h" +#include "flutter/shell/testing/testing.h" #include "lib/fxl/command_line.h" #include "lib/fxl/logging.h" +#include "lib/tonic/dart_microtask_queue.h" -int main(int argc, const char* argv[]) { +// Exit codes used by the Dart command line tool. +const int kApiErrorExitCode = 253; +const int kCompilationErrorExitCode = 254; +const int kErrorExitCode = 255; + +// Checks whether the engine's main Dart isolate has no pending work. If so, +// then exit the given message loop. +class ScriptCompletionTaskObserver : public fml::TaskObserver { + public: + ScriptCompletionTaskObserver(fxl::RefPtr task_runner) + : main_task_runner_(std::move(task_runner)), + prev_live_(false), + last_error_(tonic::kNoError) {} + + void DidProcessTask() override { + shell::TestRunner& test_runner = shell::TestRunner::Shared(); + shell::Engine& engine = test_runner.platform_view().engine(); + + if (engine.GetLoadScriptError() != tonic::kNoError) { + last_error_ = engine.GetLoadScriptError(); + main_task_runner_->PostTask([]() { fml::MessageLoop::GetCurrent().Terminate(); }); + return; + } + + bool live = engine.UIIsolateHasLivePorts(); + if (prev_live_ && !live) { + last_error_ = engine.GetUIIsolateLastError(); + main_task_runner_->PostTask([]() { fml::MessageLoop::GetCurrent().Terminate(); }); + } + prev_live_ = live; + } + + tonic::DartErrorHandleType last_error() { return last_error_; } + + private: + fxl::RefPtr main_task_runner_; + bool prev_live_; + tonic::DartErrorHandleType last_error_; +}; + +int ConvertErrorTypeToExitCode(tonic::DartErrorHandleType error) { + switch (error) { + case tonic::kCompilationErrorType: + return kCompilationErrorExitCode; + case tonic::kApiErrorType: + return kApiErrorExitCode; + case tonic::kUnknownErrorType: + return kErrorExitCode; + default: + return 0; + } +} + +static fxl::CommandLine InitializedCommandLine() { std::vector args_vector; for (NSString* arg in [NSProcessInfo processInfo].arguments) { args_vector.emplace_back(arg.UTF8String); } - auto command_line = fxl::CommandLineFromIterators(args_vector.begin(), args_vector.end()); + return fxl::CommandLineFromIterators(args_vector.begin(), args_vector.end()); +} + +int main(int argc, const char* argv[]) { + [FlutterApplication sharedApplication]; + + // Can't use shell::Shell::Shared().GetCommandLine() because it is initialized only + // in shell::PlatformMacMain call below. + auto command_line = InitializedCommandLine(); + + std::string bundle_path = ""; + command_line.GetOptionValue(FlagForSwitch(shell::Switch::FlutterAssetsDir), &bundle_path); + + shell::PlatformMacMain("", "", bundle_path); // Print help. if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { @@ -28,7 +99,36 @@ int main(int argc, const char* argv[]) { return EXIT_SUCCESS; } - [NSApplication sharedApplication].delegate = - [[[FlutterApplicationDelegate alloc] init] autorelease]; - return NSApplicationMain(argc, argv); + // Decide between interactive and non-interactive modes. + if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::NonInteractive))) { + if (!shell::InitForTesting(std::move(command_line))) + return 1; + + // Note that this task observer must be added after the observer that drains + // the microtask queue. + ScriptCompletionTaskObserver task_observer(fml::MessageLoop::GetCurrent().GetTaskRunner()); + blink::Threads::UI()->PostTask( + [&task_observer] { fml::MessageLoop::GetCurrent().AddTaskObserver(&task_observer); }); + + fml::MessageLoop::GetCurrent().Run(); + + shell::TestRunner& test_runner = shell::TestRunner::Shared(); + tonic::DartErrorHandleType error = test_runner.platform_view().engine().GetLoadScriptError(); + if (error == tonic::kNoError) + error = task_observer.last_error(); + if (error == tonic::kNoError) { + fxl::AutoResetWaitableEvent latch; + blink::Threads::UI()->PostTask([&error, &latch] { + error = tonic::DartMicrotaskQueue::GetForCurrentThread()->GetLastError(); + latch.Signal(); + }); + latch.Wait(); + } + + // The script has completed and the engine may not be in a clean state, + // so just stop the process. + exit(ConvertErrorTypeToExitCode(error)); + } else { + return NSApplicationMain(argc, argv); + } } diff --git a/shell/platform/darwin/desktop/platform_view_mac.h b/shell/platform/darwin/desktop/platform_view_mac.h index d4b19b94d1d99..501400b6803d4 100644 --- a/shell/platform/darwin/desktop/platform_view_mac.h +++ b/shell/platform/darwin/desktop/platform_view_mac.h @@ -7,7 +7,6 @@ #include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/platform_view.h" -#include "flutter/shell/common/shell.h" #include "flutter/shell/gpu/gpu_surface_gl.h" #include "lib/fxl/memory/weak_ptr.h" @@ -16,13 +15,15 @@ namespace shell { -class PlatformViewMac final : public PlatformView, public GPUSurfaceGLDelegate { +class PlatformViewMac : public PlatformView, public GPUSurfaceGLDelegate { public: - PlatformViewMac(Shell& shell, NSOpenGLView* gl_view); + PlatformViewMac(NSOpenGLView* gl_view); ~PlatformViewMac() override; - std::unique_ptr CreateVSyncWaiter() override; + virtual void Attach() override; + + void SetupAndLoadDart(); bool GLContextMakeCurrent() override; @@ -32,17 +33,27 @@ class PlatformViewMac final : public PlatformView, public GPUSurfaceGLDelegate { intptr_t GLContextFBO() const override; + VsyncWaiter* GetVsyncWaiter() override; + + bool ResourceContextMakeCurrent() override; + + void RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) override; + + void SetAssetBundlePath(const std::string& assets_directory) override; + private: fml::scoped_nsobject opengl_view_; fml::scoped_nsobject resource_loading_context_; bool IsValid() const; - // |shell::PlatformView| - std::unique_ptr CreateRenderingSurface() override; + void SetupAndLoadFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages); - // |shell::PlatformView| - sk_sp CreateResourceContext() const override; + void SetAssetBundlePathOnUI(const std::string& assets_directory); FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewMac); }; diff --git a/shell/platform/darwin/desktop/platform_view_mac.mm b/shell/platform/darwin/desktop/platform_view_mac.mm index f25fa6945af23..42948386fbcd4 100644 --- a/shell/platform/darwin/desktop/platform_view_mac.mm +++ b/shell/platform/darwin/desktop/platform_view_mac.mm @@ -7,26 +7,77 @@ #include #include +#include "flutter/common/threads.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/common/io_manager.h" -#include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/switches.h" +#include "flutter/shell/gpu/gpu_rasterizer.h" +#include "flutter/shell/platform/darwin/common/platform_mac.h" +#include "flutter/shell/platform/darwin/common/process_info_mac.h" #include "flutter/shell/platform/darwin/desktop/vsync_waiter_mac.h" #include "lib/fxl/command_line.h" #include "lib/fxl/synchronization/waitable_event.h" namespace shell { -PlatformViewMac::PlatformViewMac(Shell& shell, NSOpenGLView* gl_view) - : PlatformView(shell, shell.GetTaskRunners()), +PlatformViewMac::PlatformViewMac(NSOpenGLView* gl_view) + : PlatformView(std::make_unique(std::make_unique())), opengl_view_([gl_view retain]), resource_loading_context_([[NSOpenGLContext alloc] initWithFormat:gl_view.pixelFormat shareContext:gl_view.openGLContext]) {} PlatformViewMac::~PlatformViewMac() = default; -std::unique_ptr PlatformViewMac::CreateVSyncWaiter() { - return std::make_unique(task_runners_); +void PlatformViewMac::Attach() { + CreateEngine(); +} + +void PlatformViewMac::SetupAndLoadDart() { + if (AttemptLaunchFromCommandLineSwitches(&engine())) { + // This attempts launching from a Flutter assets directory that does not + // contain a dart snapshot. + return; + } + + const auto& command_line = shell::Shell::Shared().GetCommandLine(); + + std::string bundle_path = + command_line.GetOptionValueWithDefault(FlagForSwitch(Switch::FlutterAssetsDir), ""); + if (!bundle_path.empty()) { + blink::Threads::UI()->PostTask([ engine = engine().GetWeakPtr(), bundle_path ] { + if (engine) + engine->RunBundle(bundle_path); + }); + return; + } + + auto args = command_line.positional_args(); + if (args.size() > 0) { + std::string main = args[0]; + std::string packages = + command_line.GetOptionValueWithDefault(FlagForSwitch(Switch::Packages), ""); + blink::Threads::UI()->PostTask([ engine = engine().GetWeakPtr(), main, packages ] { + if (engine) + engine->RunBundleAndSource(std::string(), main, packages); + }); + return; + } +} + +void PlatformViewMac::SetupAndLoadFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) { + blink::Threads::UI()->PostTask( + [ engine = engine().GetWeakPtr(), assets_directory, main, packages ] { + if (engine) + engine->RunBundleAndSource(assets_directory, main, packages); + }); +} + +void PlatformViewMac::SetAssetBundlePathOnUI(const std::string& assets_directory) { + blink::Threads::UI()->PostTask([ engine = engine().GetWeakPtr(), assets_directory ] { + if (engine) + engine->SetAssetBundlePath(assets_directory); + }); } intptr_t PlatformViewMac::GLContextFBO() const { @@ -64,9 +115,21 @@ return true; } -sk_sp PlatformViewMac::CreateResourceContext() const { - [resource_loading_context_.get() makeCurrentContext]; - return IOManager::CreateCompatibleResourceLoadingContext(GrBackend::kOpenGL_GrBackend); +VsyncWaiter* PlatformViewMac::GetVsyncWaiter() { + if (!vsync_waiter_) + vsync_waiter_ = std::make_unique(); + return vsync_waiter_.get(); +} + +bool PlatformViewMac::ResourceContextMakeCurrent() { + NSOpenGLContext* context = resource_loading_context_.get(); + + if (context == nullptr) { + return false; + } + + [context makeCurrentContext]; + return true; } bool PlatformViewMac::IsValid() const { @@ -83,8 +146,30 @@ return true; } -std::unique_ptr PlatformViewMac::CreateRenderingSurface() { - return std::make_unique(this); +void PlatformViewMac::RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) { + auto latch = new fxl::ManualResetWaitableEvent(); + + dispatch_async(dispatch_get_main_queue(), ^{ + SetupAndLoadFromSource(assets_directory, main, packages); + latch->Signal(); + }); + + latch->Wait(); + delete latch; +} + +void PlatformViewMac::SetAssetBundlePath(const std::string& assets_directory) { + auto latch = new fxl::ManualResetWaitableEvent(); + + dispatch_async(dispatch_get_main_queue(), ^{ + SetAssetBundlePathOnUI(assets_directory); + latch->Signal(); + }); + + latch->Wait(); + delete latch; } } // namespace shell diff --git a/shell/platform/darwin/desktop/vsync_waiter_mac.cc b/shell/platform/darwin/desktop/vsync_waiter_mac.cc index 0ccadaf42754d..a28ff62edb918 100644 --- a/shell/platform/darwin/desktop/vsync_waiter_mac.cc +++ b/shell/platform/darwin/desktop/vsync_waiter_mac.cc @@ -6,14 +6,14 @@ #include +#include "flutter/common/threads.h" #include "lib/fxl/logging.h" namespace shell { #define link_ (reinterpret_cast(opaque_)) -VsyncWaiterMac::VsyncWaiterMac(blink::TaskRunners task_runners) - : VsyncWaiter(std::move(task_runners)), opaque_(nullptr) { +VsyncWaiterMac::VsyncWaiterMac() : opaque_(nullptr) { // Create the link. CVDisplayLinkRef link = nullptr; CVDisplayLinkCreateWithActiveCGDisplays(&link); @@ -48,10 +48,18 @@ void VsyncWaiterMac::OnDisplayLink() { CVDisplayLinkStop(link_); - FireCallback(frame_start_time, frame_target_time); + auto callback = std::move(callback_); + callback_ = Callback(); + + blink::Threads::UI()->PostTask( + [callback, frame_start_time, frame_target_time] { + callback(frame_start_time, frame_target_time); + }); } -void VsyncWaiterMac::AwaitVSync() { +void VsyncWaiterMac::AsyncWaitForVsync(Callback callback) { + FXL_DCHECK(!callback_); + callback_ = std::move(callback); CVDisplayLinkStart(link_); } diff --git a/shell/platform/darwin/desktop/vsync_waiter_mac.h b/shell/platform/darwin/desktop/vsync_waiter_mac.h index 0ad929a509ea3..15f551f212901 100644 --- a/shell/platform/darwin/desktop/vsync_waiter_mac.h +++ b/shell/platform/darwin/desktop/vsync_waiter_mac.h @@ -10,19 +10,19 @@ namespace shell { -class VsyncWaiterMac final : public VsyncWaiter { +class VsyncWaiterMac : public VsyncWaiter { public: - VsyncWaiterMac(blink::TaskRunners task_runners); + VsyncWaiterMac(); ~VsyncWaiterMac() override; + void AsyncWaitForVsync(Callback callback) override; + private: void* opaque_; - - void AwaitVSync() override; + Callback callback_; static void OnDisplayLink(void* context); - void OnDisplayLink(); FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterMac); diff --git a/shell/platform/darwin/ios/BUILD.gn b/shell/platform/darwin/ios/BUILD.gn index 8946ee954c23a..310af79c2ed8e 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -40,6 +40,8 @@ shared_library("create_flutter_framework_dylib") { "framework/Source/FlutterDartProject.mm", "framework/Source/FlutterDartProject_Internal.h", "framework/Source/FlutterHeadlessDartRunner.mm", + "framework/Source/FlutterDartSource.h", + "framework/Source/FlutterDartSource.mm", "framework/Source/FlutterNavigationController.mm", "framework/Source/FlutterPlatformPlugin.h", "framework/Source/FlutterPlatformPlugin.mm", @@ -51,15 +53,14 @@ shared_library("create_flutter_framework_dylib") { "framework/Source/FlutterView.h", "framework/Source/FlutterView.mm", "framework/Source/FlutterViewController.mm", - "framework/Source/FlutterViewController_Internal.h", "framework/Source/accessibility_bridge.h", "framework/Source/accessibility_bridge.mm", "framework/Source/accessibility_text_entry.h", "framework/Source/accessibility_text_entry.mm", + "framework/Source/flutter_main_ios.h", + "framework/Source/flutter_main_ios.mm", "framework/Source/flutter_touch_mapper.h", "framework/Source/flutter_touch_mapper.mm", - "framework/Source/platform_message_response_darwin.h", - "framework/Source/platform_message_response_darwin.mm", "framework/Source/platform_message_router.h", "framework/Source/platform_message_router.mm", "framework/Source/vsync_waiter_ios.h", @@ -85,7 +86,6 @@ shared_library("create_flutter_framework_dylib") { "$flutter_root/fml", "$flutter_root/glue", "$flutter_root/lib/ui", - "$flutter_root/runtime", "$flutter_root/shell/common", "$flutter_root/shell/gpu", "$flutter_root/shell/platform/darwin/common", @@ -95,10 +95,7 @@ shared_library("create_flutter_framework_dylib") { "//third_party/skia", ] if (flutter_runtime_mode == "debug") { - deps += [ - "$flutter_root/lib/snapshot", - "//third_party/dart/runtime:libdart_jit", - ] + deps += [ "//third_party/dart/runtime:libdart_jit" ] } else { deps += [ "//third_party/dart/runtime:libdart_precompiled_runtime" ] } diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm b/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm index 3c613c9fbad8f..d5f30d02664d9 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm @@ -2,121 +2,42 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" -#include "flutter/common/task_runners.h" -#include "flutter/fml/message_loop.h" -#include "flutter/fml/platform/darwin/scoped_nsobject.h" -#include "flutter/runtime/dart_vm.h" +#include "flutter/common/threads.h" #include "flutter/shell/common/shell.h" #include "flutter/shell/common/switches.h" -#include "flutter/shell/platform/darwin/common/command_line.h" -#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" - -static const char* kScriptSnapshotFileName = "snapshot_blob.bin"; -static const char* kVMKernelSnapshotFileName = "platform.dill"; -static const char* kApplicationKernelSnapshotFileName = "kernel_blob.bin"; - -static blink::Settings DefaultSettingsForProcess() { - auto command_line = shell::CommandLineFromNSProcessInfo(); - - // Settings passed in explicitly via command line arguments take priority. - auto settings = shell::SettingsFromCommandLine(command_line); - - settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { - fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); - }; - - settings.task_observer_remove = [](intptr_t key) { - fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); - }; - - // The command line arguments may not always be complete. If they aren't, attempt to fill in - // defaults. - - // Flutter ships the ICU data file in the the bundle of the engine. Look for it there. - if (settings.icu_data_path.size() == 0) { - NSBundle* bundle = [NSBundle bundleForClass:[FlutterViewController class]]; - NSString* icuDataPath = [bundle pathForResource:@"icudtl" ofType:@"dat"]; - if (icuDataPath.length > 0) { - settings.icu_data_path = icuDataPath.UTF8String; - } +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h" +#include "lib/fxl/strings/string_view.h" +#include "third_party/dart/runtime/include/dart_api.h" + +static NSURL* URLForSwitch(const fxl::StringView name) { + const auto& cmd = shell::Shell::Shared().GetCommandLine(); + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + + std::string switch_value; + if (cmd.GetOptionValue(name, &switch_value)) { + auto url = [NSURL fileURLWithPath:@(switch_value.c_str())]; + [defaults setURL:url forKey:@(name.data())]; + [defaults synchronize]; + return url; } - if (blink::DartVM::IsRunningPrecompiledCode()) { - // The application bundle could be specified in the Info.plist. - if (settings.application_library_path.size() == 0) { - NSString* libraryName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTLibraryPath"]; - NSString* libraryPath = [[NSBundle mainBundle] pathForResource:libraryName ofType:nil]; - if (libraryPath.length > 0) { - settings.application_library_path = - [NSBundle bundleWithPath:libraryPath].executablePath.UTF8String; - } - } - - // In case the application bundle is still not specified, look for the App.framework in the - // Frameworks directory. - if (settings.application_library_path.size() == 0) { - NSString* applicationFrameworkPath = - [[NSBundle mainBundle] pathForResource:@"Frameworks/App.framework" ofType:@""]; - if (applicationFrameworkPath.length > 0) { - settings.application_library_path = - [NSBundle bundleWithPath:applicationFrameworkPath].executablePath.UTF8String; - } - } - } + return [defaults URLForKey:@(name.data())]; +} - // Checks to see if the flutter assets directory is already present. - if (settings.assets_path.size() == 0) { - NSString* assetsPath = [[NSBundle mainBundle] pathForResource:@"flutter_assets" ofType:@""]; - - if (assetsPath.length > 0) { - settings.assets_path = assetsPath.UTF8String; - - if (!blink::DartVM::IsRunningPrecompiledCode()) { - // Looking for the various script and kernel snapshot buffers only makes sense if we have a - // VM that can use these buffers. - { - // Check if there is a script snapshot in the assets directory we could potentially use. - NSURL* scriptSnapshotURL = [NSURL URLWithString:@(kScriptSnapshotFileName) - relativeToURL:[NSURL fileURLWithPath:assetsPath]]; - if ([[NSFileManager defaultManager] fileExistsAtPath:scriptSnapshotURL.path]) { - settings.script_snapshot_path = scriptSnapshotURL.path.UTF8String; - } - } - - { - // Check if there is a VM kernel snapshot in the assets directory we could potentially - // use. - NSURL* vmKernelSnapshotURL = [NSURL URLWithString:@(kVMKernelSnapshotFileName) - relativeToURL:[NSURL fileURLWithPath:assetsPath]]; - if ([[NSFileManager defaultManager] fileExistsAtPath:vmKernelSnapshotURL.path]) { - settings.kernel_snapshot_path = vmKernelSnapshotURL.path.UTF8String; - } - } - - { - // Check if there is an application kernel snapshot in the assets directory we could - // potentially use. - NSURL* applicationKernelSnapshotURL = - [NSURL URLWithString:@(kApplicationKernelSnapshotFileName) - relativeToURL:[NSURL fileURLWithPath:assetsPath]]; - if ([[NSFileManager defaultManager] fileExistsAtPath:applicationKernelSnapshotURL.path]) { - settings.application_kernel_asset = applicationKernelSnapshotURL.path.UTF8String; - } - } - } - } - } +@implementation FlutterDartProject { + NSBundle* _precompiledDartBundle; + FlutterDartSource* _dartSource; - return settings; + VMType _vmTypeRequirement; } -@implementation FlutterDartProject { - fml::scoped_nsobject _precompiledDartBundle; - blink::Settings _settings; ++ (void)initialize { + if (self == [FlutterDartProject class]) { + shell::FlutterMain(); + } } #pragma mark - Override base class designated initializers @@ -131,16 +52,9 @@ - (instancetype)initWithPrecompiledDartBundle:(NSBundle*)bundle { self = [super init]; if (self) { - _precompiledDartBundle.reset([bundle retain]); + _precompiledDartBundle = [bundle retain]; - _settings = DefaultSettingsForProcess(); - - if (bundle != nil) { - NSString* executablePath = _precompiledDartBundle.get().executablePath; - if ([[NSFileManager defaultManager] fileExistsAtPath:executablePath]) { - _settings.application_library_path = executablePath.UTF8String; - } - } + [self checkReadiness]; } return self; @@ -152,15 +66,11 @@ - (instancetype)initWithFlutterAssets:(NSURL*)flutterAssetsURL self = [super init]; if (self) { - _settings = DefaultSettingsForProcess(); + _dartSource = [[FlutterDartSource alloc] initWithDartMain:dartMainURL + packages:dartPackages + flutterAssets:flutterAssetsURL]; - if ([[NSFileManager defaultManager] fileExistsAtPath:dartMainURL.path]) { - _settings.main_dart_file_path = dartMainURL.path.UTF8String; - } - - if ([[NSFileManager defaultManager] fileExistsAtPath:dartPackages.path]) { - _settings.packages_file_path = dartPackages.path.UTF8String; - } + [self checkReadiness]; } return self; @@ -170,17 +80,10 @@ - (instancetype)initWithFlutterAssetsWithScriptSnapshot:(NSURL*)flutterAssetsURL self = [super init]; if (self) { - _settings = DefaultSettingsForProcess(); + _dartSource = + [[FlutterDartSource alloc] initWithFlutterAssetsWithScriptSnapshot:flutterAssetsURL]; - if ([[NSFileManager defaultManager] fileExistsAtPath:flutterAssetsURL.path]) { - _settings.assets_path = flutterAssetsURL.path.UTF8String; - - NSURL* scriptSnapshotPath = - [NSURL URLWithString:@(kScriptSnapshotFileName) relativeToURL:flutterAssetsURL]; - if ([[NSFileManager defaultManager] fileExistsAtPath:scriptSnapshotPath.path]) { - _settings.script_snapshot_path = scriptSnapshotPath.path.UTF8String; - } - } + [self checkReadiness]; } return self; @@ -189,19 +92,56 @@ - (instancetype)initWithFlutterAssetsWithScriptSnapshot:(NSURL*)flutterAssetsURL #pragma mark - Convenience initializers - (instancetype)initFromDefaultSourceForConfiguration { - if (blink::DartVM::IsRunningPrecompiledCode()) { - return [self initWithPrecompiledDartBundle:nil]; + NSBundle* bundle = [NSBundle mainBundle]; + + if (Dart_IsPrecompiledRuntime()) { + // Load from an AOTC snapshot. + return [self initWithPrecompiledDartBundle:bundle]; } else { - return [self initWithFlutterAssets:nil dartMain:nil packages:nil]; + // Load directly from sources if the appropriate command line flags are + // specified. If not, try loading from a script snapshot in the framework + // bundle. + NSURL* flutterAssetsURL = URLForSwitch(shell::FlagForSwitch(shell::Switch::FlutterAssetsDir)); + + if (flutterAssetsURL == nil) { + // If the URL was not specified on the command line, look inside the + // FlutterApplication bundle. + NSString* flutterAssetsPath = [FlutterDartProject pathForFlutterAssetsFromBundle:bundle]; + if (flutterAssetsPath != nil) { + flutterAssetsURL = [NSURL fileURLWithPath:flutterAssetsPath isDirectory:NO]; + } + } + + if (flutterAssetsURL == nil) { + NSLog(@"Error: flutterAssets directory not present in bundle; unable to start app."); + [self release]; + return nil; + } + + NSURL* dartMainURL = URLForSwitch(shell::FlagForSwitch(shell::Switch::MainDartFile)); + NSURL* dartPackagesURL = URLForSwitch(shell::FlagForSwitch(shell::Switch::Packages)); + + return + [self initWithFlutterAssets:flutterAssetsURL dartMain:dartMainURL packages:dartPackagesURL]; } -} -- (const blink::Settings&)settings { - return _settings; + NSAssert(NO, @"Unreachable"); + [self release]; + return nil; } -- (shell::RunConfiguration)runConfiguration { - return shell::RunConfiguration::InferFromSettings(_settings); +#pragma mark - Common initialization tasks + +- (void)checkReadiness { + if (_precompiledDartBundle != nil) { + _vmTypeRequirement = VMTypePrecompilation; + return; + } + + if (_dartSource != nil) { + _vmTypeRequirement = VMTypeInterpreter; + return; + } } #pragma mark - Assets-related utilities @@ -221,7 +161,7 @@ + (NSString*)pathForFlutterAssetsFromBundle:(NSBundle*)bundle { } + (NSString*)lookupKeyForAsset:(NSString*)asset { - NSString* flutterAssetsName = [FlutterDartProject flutterAssetsName:[NSBundle mainBundle]]; + NSString* flutterAssetsName = [FlutterDartProject flutterAssetsName: [NSBundle mainBundle]]; return [NSString stringWithFormat:@"%@/%@", flutterAssetsName, asset]; } @@ -229,4 +169,179 @@ + (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package { return [self lookupKeyForAsset:[NSString stringWithFormat:@"packages/%@/%@", package, asset]]; } +#pragma mark - Launching the project in a preconfigured engine. + +static NSString* NSStringFromVMType(VMType type) { + switch (type) { + case VMTypeInvalid: + return @"Invalid"; + case VMTypeInterpreter: + return @"Interpreter"; + case VMTypePrecompilation: + return @"Precompilation"; + } + + return @"Unknown"; +} + +- (void)launchInEngine:(shell::Engine*)engine + withEntrypoint:(NSString*)entrypoint + embedderVMType:(VMType)embedderVMType + result:(LaunchResult)result { + if (_vmTypeRequirement == VMTypeInvalid) { + result(NO, @"The Dart project is invalid and cannot be loaded by any VM."); + return; + } + + if (embedderVMType == VMTypeInvalid) { + result(NO, @"The embedder is invalid."); + return; + } + + if (_vmTypeRequirement != embedderVMType) { + NSString* message = + [NSString stringWithFormat: + @"Could not load the project because of differing project type. " + @"The project can run in '%@' but the embedder is configured as " + @"'%@'", + NSStringFromVMType(_vmTypeRequirement), NSStringFromVMType(embedderVMType)]; + result(NO, message); + return; + } + + switch (_vmTypeRequirement) { + case VMTypeInterpreter: + [self runFromSourceInEngine:engine withEntrypoint:entrypoint result:result]; + return; + case VMTypePrecompilation: + [self runFromPrecompiledSourceInEngine:engine withEntrypoint:entrypoint result:result]; + return; + case VMTypeInvalid: + break; + } + + return result(NO, @"Internal error"); +} + +- (void)launchInEngine:(shell::Engine*)engine + embedderVMType:(VMType)embedderVMType + result:(LaunchResult)result { + if (_vmTypeRequirement == VMTypeInvalid) { + result(NO, @"The Dart project is invalid and cannot be loaded by any VM."); + return; + } + + if (embedderVMType == VMTypeInvalid) { + result(NO, @"The embedder is invalid."); + return; + } + + if (_vmTypeRequirement != embedderVMType) { + NSString* message = + [NSString stringWithFormat: + @"Could not load the project because of differing project type. " + @"The project can run in '%@' but the embedder is configured as " + @"'%@'", + NSStringFromVMType(_vmTypeRequirement), NSStringFromVMType(embedderVMType)]; + result(NO, message); + return; + } + + switch (_vmTypeRequirement) { + case VMTypeInterpreter: + [self runFromSourceInEngine:engine withEntrypoint:@"main" result:result]; + return; + case VMTypePrecompilation: + [self runFromPrecompiledSourceInEngine:engine withEntrypoint:@"main" result:result]; + return; + case VMTypeInvalid: + break; + } + + return result(NO, @"Internal error"); +} + +#pragma mark - Running from precompiled application bundles + +- (void)runFromPrecompiledSourceInEngine:(shell::Engine*)engine + withEntrypoint:(NSString*)entrypoint + result:(LaunchResult)result { + if (![_precompiledDartBundle load]) { + NSString* message = [NSString + stringWithFormat:@"Could not load the framework ('%@') containing precompiled code.", + _precompiledDartBundle.bundleIdentifier]; + result(NO, message); + return; + } + + NSString* path = [FlutterDartProject pathForFlutterAssetsFromBundle:_precompiledDartBundle]; + if (path.length == 0) { + NSString* message = [NSString stringWithFormat: + @"Could not find the 'flutter_assets' dir in " + @"the precompiled Dart bundle with ID '%@'", + _precompiledDartBundle.bundleIdentifier]; + result(NO, message); + return; + } + + std::string bundle_path = path.UTF8String; + blink::Threads::UI()->PostTask([ + engine = engine->GetWeakPtr(), bundle_path, entrypoint = std::string([entrypoint UTF8String]) + ] { + if (engine) + engine->RunBundle(bundle_path, entrypoint); + }); + + result(YES, @"Success"); +} + +#pragma mark - Running from source + +- (void)runFromSourceInEngine:(shell::Engine*)engine + withEntrypoint:(NSString*)entrypoint + result:(LaunchResult)result { + if (_dartSource == nil) { + result(NO, @"Dart source not specified."); + return; + } + + [_dartSource validate:^(BOOL success, NSString* message) { + if (!success) { + return result(NO, message); + } + + std::string bundle_path = _dartSource.flutterAssets.absoluteURL.path.UTF8String; + + if (_dartSource.assetsDirContainsScriptSnapshot) { + blink::Threads::UI()->PostTask([ + engine = engine->GetWeakPtr(), bundle_path, + entrypoint = std::string([entrypoint UTF8String]) + ] { + if (engine) + engine->RunBundle(bundle_path, entrypoint); + }); + } else { + std::string main = _dartSource.dartMain.absoluteURL.path.UTF8String; + std::string packages = _dartSource.packages.absoluteURL.path.UTF8String; + blink::Threads::UI()->PostTask( + [ engine = engine->GetWeakPtr(), bundle_path, main, packages ] { + if (engine) + engine->RunBundleAndSource(bundle_path, main, packages); + }); + } + + result(YES, @"Success"); + }]; +} + +#pragma mark - Misc. + +- (void)dealloc { + [_precompiledDartBundle unload]; + [_precompiledDartBundle release]; + [_dartSource release]; + + [super dealloc]; +} + @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h index 7fe1fc364f328..75db7c4049dd9 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h @@ -5,15 +5,32 @@ #ifndef SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTPROJECT_INTERNAL_H_ #define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTPROJECT_INTERNAL_H_ -#include "flutter/common/settings.h" #include "flutter/shell/common/engine.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterDartProject.h" +enum VMType { + // An invalid VM configuration. + VMTypeInvalid = 0, + // VM can execute Dart code as an interpreter. + VMTypeInterpreter, + // VM can execute precompiled Dart code. + VMTypePrecompilation, +}; + +typedef void (^LaunchResult)(BOOL success, NSString* message); + @interface FlutterDartProject () -- (const blink::Settings&)settings; +- (void)launchInEngine:(shell::Engine*)engine + embedderVMType:(VMType)type + result:(LaunchResult)result; + +- (void)launchInEngine:(shell::Engine*)engine + withEntrypoint:(NSString*)entrypoint + embedderVMType:(VMType)type + result:(LaunchResult)result; -- (shell::RunConfiguration)runConfiguration; ++ (NSString*)pathForFlutterAssetsFromBundle:(NSBundle*)bundle; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h b/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h new file mode 100644 index 0000000000000..c3881ce065185 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h @@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium 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 SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTSOURCE_H_ +#define SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTSOURCE_H_ + +#import + +typedef void (^ValidationResult)(BOOL result, NSString* message); + +@interface FlutterDartSource : NSObject + +@property(nonatomic, readonly) NSURL* dartMain; +@property(nonatomic, readonly) NSURL* packages; +@property(nonatomic, readonly) NSURL* flutterAssets; +@property(nonatomic, readonly) BOOL assetsDirContainsScriptSnapshot; + +- (instancetype)initWithDartMain:(NSURL*)dartMain + packages:(NSURL*)packages + flutterAssets:(NSURL*)flutterAssets NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithFlutterAssetsWithScriptSnapshot:(NSURL*)flutterAssets + NS_DESIGNATED_INITIALIZER; + +- (void)validate:(ValidationResult)result; + +@end + +#endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTERDARTSOURCE_H_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm b/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm new file mode 100644 index 0000000000000..aecb4e5806b3a --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm @@ -0,0 +1,100 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h" + +@implementation FlutterDartSource + +@synthesize dartMain = _dartMain; +@synthesize packages = _packages; +@synthesize flutterAssets = _flutterAssets; +@synthesize assetsDirContainsScriptSnapshot = _assetsDirContainsScriptSnapshot; + +#pragma mark - Convenience Initializers + +- (instancetype)init { + return [self initWithDartMain:nil packages:nil flutterAssets:nil]; +} + +#pragma mark - Designated Initializers + +- (instancetype)initWithDartMain:(NSURL*)dartMain + packages:(NSURL*)packages + flutterAssets:(NSURL*)flutterAssets { + self = [super init]; + + if (self) { + _dartMain = [dartMain copy]; + _packages = [packages copy]; + _flutterAssets = [flutterAssets copy]; + + NSFileManager* fileManager = [NSFileManager defaultManager]; + + const BOOL dartMainExists = [fileManager fileExistsAtPath:dartMain.absoluteURL.path]; + const BOOL packagesExists = [fileManager fileExistsAtPath:packages.absoluteURL.path]; + + if (!dartMainExists || !packagesExists) { + // We cannot actually verify this without opening up the directory. This is + // just an assumption. + _assetsDirContainsScriptSnapshot = YES; + } + } + + return self; +} + +- (instancetype)initWithFlutterAssetsWithScriptSnapshot:(NSURL*)flutterAssets { + self = [super init]; + + if (self) { + _flutterAssets = [flutterAssets copy]; + _assetsDirContainsScriptSnapshot = YES; + } + + return self; +} + +static BOOL CheckDartProjectURL(NSMutableString* log, NSURL* url, NSString* logLabel) { + if (url == nil) { + [log appendFormat:@"The %@ was not specified.\n", logLabel]; + return false; + } + + if (!url.isFileURL) { + [log appendFormat:@"The %@ must be a file URL.\n", logLabel]; + return false; + } + + if (![[NSFileManager defaultManager] fileExistsAtPath:url.absoluteURL.path]) { + [log appendFormat:@"No file found at '%@' when looking for the %@.\n", url, logLabel]; + return false; + } + + return true; +} + +- (void)validate:(ValidationResult)result { + NSMutableString* log = [[[NSMutableString alloc] init] autorelease]; + + BOOL isValid = YES; + + isValid &= CheckDartProjectURL(log, _flutterAssets, @"Flutter assets"); + + if (!_assetsDirContainsScriptSnapshot) { + isValid &= CheckDartProjectURL(log, _dartMain, @"Dart main"); + isValid &= CheckDartProjectURL(log, _packages, @"Dart packages"); + } + + result(isValid, log); +} + +- (void)dealloc { + [_dartMain release]; + [_packages release]; + [_flutterAssets release]; + + [super dealloc]; +} + +@end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm index dee11d08934a5..2143f362f7905 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm @@ -2,84 +2,38 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - #import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterHeadlessDartRunner.h" -#include #include -#include "flutter/fml/message_loop.h" -#include "flutter/shell/common/engine.h" -#include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/run_configuration.h" -#include "flutter/shell/common/shell.h" -#include "flutter/shell/common/switches.h" -#include "flutter/shell/common/thread_host.h" -#include "flutter/shell/platform/darwin/common/command_line.h" -#include "lib/fxl/functional/make_copyable.h" +#include "flutter/fml/platform/darwin/scoped_nsobject.h" +#include "flutter/shell/common/null_platform_view.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" -static std::unique_ptr CreateHeadlessPlatformView(shell::Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); -} +@interface FlutterHeadlessDartRunner () +@end -static std::unique_ptr CreateHeadlessRasterizer(shell::Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); +@implementation FlutterHeadlessDartRunner { + fml::scoped_nsprotocol _dartProject; + std::shared_ptr _platformView; } -@implementation FlutterHeadlessDartRunner { - shell::ThreadHost _threadHost; - std::unique_ptr _shell; +- (instancetype)init { + _dartProject.reset([[FlutterDartProject alloc] initFromDefaultSourceForConfiguration]); + _platformView = std::make_shared(); + _platformView->Attach(); + return self; } - (void)runWithEntrypoint:(NSString*)entrypoint { - if (_shell != nullptr || entrypoint.length == 0) { - FXL_LOG(ERROR) << "This headless dart runner was already used to run some code."; - return; - } - - const auto label = "io.flutter.headless"; - - // Create the threads to run the shell on. - _threadHost = { - label, // native thread label - shell::ThreadHost::Type::UI // managed threads to create - }; - - // Configure shell task runners. - auto current_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); - auto single_task_runner = _threadHost.ui_thread->GetTaskRunner(); - blink::TaskRunners task_runners(label, // dart thread label - current_task_runner, // platform - single_task_runner, // gpu - single_task_runner, // ui - single_task_runner // io - ); - - auto settings = shell::SettingsFromCommandLine(shell::CommandLineFromNSProcessInfo()); - - // Create the shell. This is a blocking operation. - _shell = shell::Shell::Create( - std::move(task_runners), // task runners - std::move(settings), // settings - std::bind(&CreateHeadlessPlatformView, std::placeholders::_1), // platform view creation - std::bind(&CreateHeadlessRasterizer, std::placeholders::_1) // rasterzier creation - ); - - if (_shell == nullptr) { - FXL_LOG(ERROR) << "Could not start a shell for the headless dart runner with entrypoint: " - << entrypoint.UTF8String; - return; - } - - // Override the default run configuration with the specified entrypoint. - _shell->GetTaskRunners().GetUITaskRunner()->PostTask( - fxl::MakeCopyable([engine = _shell->GetEngine(), - config = shell::RunConfiguration::InferFromSettings(settings)]() mutable { - if (!engine || !engine->Run(std::move(config))) { - FXL_LOG(ERROR) << "Could not launch engine with configuration."; - } - })); + const enum VMType type = Dart_IsPrecompiledRuntime() ? VMTypePrecompilation : VMTypeInterpreter; + [_dartProject launchInEngine:&_platformView->engine() + withEntrypoint:entrypoint + embedderVMType:type + result:^(BOOL success, NSString* message) { + if (!success) + NSLog(@"%@", message); + }]; } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.h b/shell/platform/darwin/ios/framework/Source/FlutterView.h index 5e3d303401725..661940620c947 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.h @@ -7,14 +7,8 @@ #include -#include - -#include "flutter/shell/platform/darwin/ios/ios_surface.h" - @interface FlutterView : UIView -- (std::unique_ptr)createSurface; - @end #endif // SHELL_PLATFORM_IOS_FRAMEWORK_SOURCE_FLUTTER_VIEW_H_ diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.mm b/shell/platform/darwin/ios/framework/Source/FlutterView.mm index 27e3d48c4cb50..7c382838c6f5c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -5,41 +5,20 @@ #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/common/settings.h" -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/flow/layers/layer_tree.h" -#include "flutter/fml/trace_event.h" #include "flutter/shell/common/platform_view.h" #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/shell.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" -#include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" -#include "flutter/shell/platform/darwin/ios/ios_surface_software.h" #include "lib/fxl/synchronization/waitable_event.h" #include "third_party/skia/include/utils/mac/SkCGUtils.h" -@interface FlutterView () +@interface FlutterView () @end @implementation FlutterView -- (FlutterViewController*)flutterViewController { - // Find the first view controller in the responder chain and see if it is a FlutterViewController. - for (UIResponder* responder = self.nextResponder; responder != nil; - responder = responder.nextResponder) { - if ([responder isKindOfClass:[UIViewController class]]) { - if ([responder isKindOfClass:[FlutterViewController class]]) { - return reinterpret_cast(responder); - } else { - // Should only happen if a non-FlutterViewController tries to somehow (via dynamic class - // resolution or reparenting) set a FlutterView as its view. - return nil; - } - } - } - return nil; -} - - (void)layoutSubviews { if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { CAEAGLLayer* layer = reinterpret_cast(self.layer); @@ -61,24 +40,13 @@ + (Class)layerClass { #endif // TARGET_IPHONE_SIMULATOR } -- (std::unique_ptr)createSurface { - if ([self.layer isKindOfClass:[CAEAGLLayer class]]) { - fml::scoped_nsobject eagl_layer( - reinterpret_cast([self.layer retain])); - return std::make_unique(std::move(eagl_layer)); - } else { - fml::scoped_nsobject layer(reinterpret_cast([self.layer retain])); - return std::make_unique(std::move(layer)); - } -} - - (BOOL)enableInputClicksWhenVisible { return YES; } -static void SnapshotRasterizer(fml::WeakPtr rasterizer, - CGContextRef context, - bool is_opaque) { +void SnapshotRasterizer(fml::WeakPtr rasterizer, + CGContextRef context, + bool is_opaque) { if (!rasterizer) { return; } @@ -109,11 +77,10 @@ static void SnapshotRasterizer(fml::WeakPtr rasterizer, SkCanvas canvas(bitmap); - flow::CompositorContext compositor_context; - - if (auto frame = compositor_context.AcquireFrame(nullptr, &canvas, false /* instrumentation */)) { - layer_tree->Preroll(*frame, true /* ignore raster cache */); - layer_tree->Paint(*frame); + { + flow::CompositorContext compositor_context(nullptr); + auto frame = compositor_context.AcquireFrame(nullptr, &canvas, false /* instrumentation */); + layer_tree->Raster(frame, false /* ignore raster cache. */); } canvas.flush(); @@ -122,6 +89,41 @@ static void SnapshotRasterizer(fml::WeakPtr rasterizer, SkCGDrawBitmap(context, bitmap, 0, 0); } +static fml::WeakPtr GetRandomRasterizer() { + fml::WeakPtr rasterizer; + shell::Shell::Shared().IteratePlatformViews([&rasterizer](shell::PlatformView* view) -> bool { + rasterizer = view->rasterizer().GetWeakRasterizerPtr(); + // We just grab the first rasterizer so there is no need to iterate + // further. + return false; + }); + return rasterizer; +} + +void SnapshotContents(CGContextRef context, bool is_opaque) { + // TODO(chinmaygarde): Currently, there is no way to get the rasterizer for + // a particular platform view from the shell. But, for now, we only have one + // platform view. So use that. Once we support multiple platform views, the + // shell will need to provide a way to get the rasterizer for a specific + // platform view. + SnapshotRasterizer(GetRandomRasterizer(), context, is_opaque); +} + +void SnapshotContentsSync(CGContextRef context, UIView* view) { + auto gpu_thread = blink::Threads::Gpu(); + + if (!gpu_thread) { + return; + } + + fxl::AutoResetWaitableEvent latch; + gpu_thread->PostTask([&latch, context, view]() { + SnapshotContents(context, [view isOpaque]); + latch.Signal(); + }); + latch.Wait(); +} + // Override the default CALayerDelegate method so that APIs that attempt to // screenshot the view display contents correctly. We cannot depend on // reading @@ -130,22 +132,7 @@ static void SnapshotRasterizer(fml::WeakPtr rasterizer, // 2: The call is made of the platform thread and not the GPU thread. // 3: There may be a software rasterizer. - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context { - TRACE_EVENT0("flutter", "SnapshotFlutterView"); - FlutterViewController* controller = [self flutterViewController]; - - if (controller == nil) { - return; - } - - auto& shell = [controller shell]; - - fxl::AutoResetWaitableEvent latch; - shell.GetTaskRunners().GetGPUTaskRunner()->PostTask( - [&latch, rasterizer = shell.GetRasterizer(), context, opaque = layer.opaque]() { - SnapshotRasterizer(std::move(rasterizer), context, opaque); - latch.Signal(); - }); - latch.Wait(); + SnapshotContentsSync(context, self); } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index 17e9a4eff48f6..a467a5a8cf1a5 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -2,54 +2,90 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - -#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" +#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" #include -#include "flutter/fml/message_loop.h" +#include "flutter/common/threads.h" +#include "flutter/flow/texture.h" #include "flutter/fml/platform/darwin/platform_version.h" +#include "flutter/fml/platform/darwin/scoped_block.h" #include "flutter/fml/platform/darwin/scoped_nsobject.h" -#include "flutter/shell/common/thread_host.h" +#include "flutter/lib/ui/painting/resource_context.h" +#include "flutter/shell/platform/darwin/common/buffer_conversions.h" +#include "flutter/shell/platform/darwin/common/platform_mac.h" +#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterCodecs.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h" #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h" #include "flutter/shell/platform/darwin/ios/framework/Source/flutter_touch_mapper.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h" +#include "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h" #include "flutter/shell/platform/darwin/ios/platform_view_ios.h" +#include "lib/fxl/functional/make_copyable.h" +#include "lib/fxl/time/time_delta.h" + +namespace { + +typedef void (^PlatformMessageResponseCallback)(NSData*); + +class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { + FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseDarwin); + + public: + void Complete(std::vector data) override { + fxl::RefPtr self(this); + blink::Threads::Platform()->PostTask( + fxl::MakeCopyable([ self, data = std::move(data) ]() mutable { + self->callback_.get()(shell::GetNSDataFromVector(data)); + })); + } + + void CompleteEmpty() override { + fxl::RefPtr self(this); + blink::Threads::Platform()->PostTask( + fxl::MakeCopyable([self]() mutable { self->callback_.get()(nil); })); + } + + private: + explicit PlatformMessageResponseDarwin(PlatformMessageResponseCallback callback) + : callback_(callback, fml::OwnershipPolicy::Retain) {} -@interface FlutterViewController () + fml::ScopedBlock callback_; +}; + +} // namespace + +@interface FlutterViewController () @end @implementation FlutterViewController { - fml::scoped_nsobject _dartProject; - shell::ThreadHost _threadHost; - std::unique_ptr _shell; - - // Channels - fml::scoped_nsobject _platformPlugin; - fml::scoped_nsobject _textInputPlugin; - fml::scoped_nsobject _localizationChannel; - fml::scoped_nsobject _navigationChannel; - fml::scoped_nsobject _platformChannel; - fml::scoped_nsobject _textInputChannel; - fml::scoped_nsobject _lifecycleChannel; - fml::scoped_nsobject _systemChannel; - fml::scoped_nsobject _settingsChannel; - - // We keep a separate reference to this and create it ahead of time because we want to be able to - // setup a shell along with its platform view before the view has to appear. - fml::scoped_nsobject _flutterView; - fml::scoped_nsobject _launchView; + fml::scoped_nsprotocol _dartProject; UIInterfaceOrientationMask _orientationPreferences; UIStatusBarStyle _statusBarStyle; blink::ViewportMetrics _viewportMetrics; shell::TouchMapper _touchMapper; + std::shared_ptr _platformView; + fml::scoped_nsprotocol _platformPlugin; + fml::scoped_nsprotocol _textInputPlugin; + fml::scoped_nsprotocol _localizationChannel; + fml::scoped_nsprotocol _navigationChannel; + fml::scoped_nsprotocol _platformChannel; + fml::scoped_nsprotocol _textInputChannel; + fml::scoped_nsprotocol _lifecycleChannel; + fml::scoped_nsprotocol _systemChannel; + fml::scoped_nsprotocol _settingsChannel; + fml::scoped_nsprotocol _launchView; int64_t _nextTextureId; BOOL _initialized; + BOOL _connected; +} + ++ (void)initialize { + if (self == [FlutterViewController class]) { + shell::FlutterMain(); + } } #pragma mark - Manage and override all designated initializers @@ -89,92 +125,26 @@ - (void)performCommonViewControllerInitialization { _orientationPreferences = UIInterfaceOrientationMaskAll; _statusBarStyle = UIStatusBarStyleDefault; - - if ([self setupShell]) { - [self setupChannels]; - [self setupNotificationCenterObservers]; - } -} - -- (shell::Shell&)shell { - FXL_DCHECK(_shell); - return *_shell; -} - -- (fml::WeakPtr)iosPlatformView { - FXL_DCHECK(_shell); - return _shell->GetPlatformView(); -} - -- (BOOL)setupShell { - FXL_DCHECK(_shell == nullptr); - - static size_t shell_count = 1; - - auto threadLabel = [NSString stringWithFormat:@"io.flutter.%zu", shell_count++]; - - _threadHost = { - threadLabel.UTF8String, // label - shell::ThreadHost::Type::UI | shell::ThreadHost::Type::GPU | shell::ThreadHost::Type::IO}; - - // The current thread will be used as the platform thread. Ensure that the message loop is - // initialized. - fml::MessageLoop::EnsureInitializedForCurrentThread(); - - blink::TaskRunners task_runners(threadLabel.UTF8String, // label - fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform - _threadHost.gpu_thread->GetTaskRunner(), // gpu - _threadHost.ui_thread->GetTaskRunner(), // ui - _threadHost.io_thread->GetTaskRunner() // io - ); - - _flutterView.reset([[FlutterView alloc] init]); - - // Lambda captures by pointers to ObjC objects are fine here because the create call is - // synchronous. - shell::Shell::CreateCallback on_create_platform_view = - [flutter_view_controller = self, flutter_view = _flutterView.get()](shell::Shell& shell) { - auto platform_view_ios = std::make_unique( - shell, // delegate - shell.GetTaskRunners(), // task runners - flutter_view_controller, // flutter view controller owner - flutter_view // flutter view owner - ); - return platform_view_ios; - }; - - shell::Shell::CreateCallback on_create_rasterizer = [](shell::Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }; - - // Create the shell. - _shell = shell::Shell::Create(std::move(task_runners), // - [_dartProject settings], // - on_create_platform_view, // - on_create_rasterizer // - ); - - if (!_shell) { - FXL_LOG(ERROR) << "Could not setup a shell to run the Dart application."; - return false; - } - - // Launch the Dart application with the inferred run configuration. - _shell->GetTaskRunners().GetUITaskRunner()->PostTask( - fxl::MakeCopyable([engine = _shell->GetEngine(), // - config = [_dartProject.get() runConfiguration] // - ]() mutable { - if (engine) { - auto result = engine->Run(std::move(config)); - if (!result) { - FXL_LOG(ERROR) << "Could not launch engine with configuration."; - } + _platformView = std::make_shared( + reinterpret_cast(self.view.layer), self); + + _platformView->Attach( + // First frame callback. + [self]() { + TRACE_EVENT0("flutter", "First Frame"); + if (_launchView) { + [UIView animateWithDuration:0.2 + animations:^{ + _launchView.get().alpha = 0; + } + completion:^(BOOL finished) { + [_launchView.get() removeFromSuperview]; + _launchView.reset(); + }]; } - })); - return true; -} + }); + _platformView->SetupResourceContextOnIOThread(); -- (void)setupChannels { _localizationChannel.reset([[FlutterMethodChannel alloc] initWithName:@"flutter/localization" binaryMessenger:self @@ -220,8 +190,9 @@ - (void)setupChannels { [_textInputChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { [_textInputPlugin.get() handleMethodCall:call result:result]; }]; - static_cast(_shell->GetPlatformView().get()) - ->SetTextInputPlugin(_textInputPlugin); + _platformView->SetTextInputPlugin(_textInputPlugin); + + [self setupNotificationCenterObservers]; } - (void)setupNotificationCenterObservers { @@ -290,24 +261,50 @@ - (void)setupNotificationCenterObservers { - (void)setInitialRoute:(NSString*)route { [_navigationChannel.get() invokeMethod:@"setInitialRoute" arguments:route]; } +#pragma mark - Initializing the engine + +- (void)alertView:(UIAlertView*)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { + exit(0); +} + +- (void)connectToEngineAndLoad { + if (_connected) + return; + _connected = YES; + + TRACE_EVENT0("flutter", "connectToEngineAndLoad"); + + // We ask the VM to check what it supports. + const enum VMType type = Dart_IsPrecompiledRuntime() ? VMTypePrecompilation : VMTypeInterpreter; + + [_dartProject launchInEngine:&_platformView->engine() + embedderVMType:type + result:^(BOOL success, NSString* message) { + if (!success) { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Launch Error" + message:message + delegate:self + cancelButtonTitle:@"OK" + otherButtonTitles:nil]; + [alert show]; + [alert release]; + } + }]; +} #pragma mark - Loading the view - (void)loadView { - self.view = _flutterView.get(); + FlutterView* view = [[FlutterView alloc] init]; + + self.view = view; self.view.multipleTouchEnabled = YES; self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [self installLaunchViewIfNecessary]; -} - -#pragma mark - Managing launch views + [view release]; -- (void)installLaunchViewIfNecessary { // Show the launch screen view again on top of the FlutterView if available. // This launch screen view will be removed once the first Flutter frame is rendered. - [_launchView.get() removeFromSuperview]; - _launchView.reset(); NSString* launchStoryboardName = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"UILaunchStoryboardName"]; if (launchStoryboardName && !self.isBeingPresented && !self.isMovingToParentViewController) { @@ -322,57 +319,16 @@ - (void)installLaunchViewIfNecessary { } } -- (void)removeLaunchViewIfPresent { - if (!_launchView) { - return; - } - - [UIView animateWithDuration:0.2 - animations:^{ - _launchView.get().alpha = 0; - } - completion:^(BOOL finished) { - [_launchView.get() removeFromSuperview]; - _launchView.reset(); - }]; -} - -- (void)installLaunchViewCallback { - if (!_shell || !_launchView) { - return; - } - auto weak_platform_view = _shell->GetPlatformView(); - if (!weak_platform_view) { - return; - } - __unsafe_unretained auto weak_flutter_view_controller = self; - // This is on the platform thread. - weak_platform_view->SetNextFrameCallback( - [weak_platform_view, weak_flutter_view_controller, - task_runner = _shell->GetTaskRunners().GetPlatformTaskRunner()]() { - // This is on the GPU thread. - task_runner->PostTask([weak_platform_view, weak_flutter_view_controller]() { - // We check if the weak platform view is alive. If it is alive, then the view controller - // also has to be alive since the view controller owns the platform view via the shell - // association. Thus, we are not convinced that the unsafe unretained weak object is in - // fact alive. - if (weak_platform_view) { - [weak_flutter_view_controller removeLaunchViewIfPresent]; - } - }); - }); -} - #pragma mark - Surface creation and teardown updates - (void)surfaceUpdated:(BOOL)appeared { + FXL_CHECK(_platformView != nullptr); + // NotifyCreated/NotifyDestroyed are synchronous and require hops between the UI and GPU thread. if (appeared) { - [self installLaunchViewCallback]; - _shell->GetPlatformView()->NotifyCreated(); - + _platformView->NotifyCreated(); } else { - _shell->GetPlatformView()->NotifyDestroyed(); + _platformView->NotifyDestroyed(); } } @@ -380,6 +336,7 @@ - (void)surfaceUpdated:(BOOL)appeared { - (void)viewWillAppear:(BOOL)animated { TRACE_EVENT0("flutter", "viewWillAppear"); + [self connectToEngineAndLoad]; // Only recreate surface on subsequent appearances when viewport metrics are known. // First time surface creation is done on viewDidLayoutSubviews. if (_viewportMetrics.physical_width) @@ -434,6 +391,8 @@ - (void)applicationWillResignActive:(NSNotification*)notification { - (void)applicationDidEnterBackground:(NSNotification*)notification { TRACE_EVENT0("flutter", "applicationDidEnterBackground"); [self surfaceUpdated:NO]; + // GrContext operations are blocked when the app is in the background. + blink::ResourceContext::Freeze(); [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.paused"]; } @@ -441,6 +400,7 @@ - (void)applicationWillEnterForeground:(NSNotification*)notification { TRACE_EVENT0("flutter", "applicationWillEnterForeground"); if (_viewportMetrics.physical_width) [self surfaceUpdated:YES]; + blink::ResourceContext::Unfreeze(); [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.inactive"]; } @@ -587,11 +547,10 @@ - (void)dispatchTouches:(NSSet*)touches phase:(UITouchPhase)phase { packet->SetPointerData(i++, pointer_data); } - _shell->GetTaskRunners().GetUITaskRunner()->PostTask( - fxl::MakeCopyable([engine = _shell->GetEngine(), packet = std::move(packet)] { - if (engine) { + blink::Threads::UI()->PostTask(fxl::MakeCopyable( + [ engine = _platformView->engine().GetWeakPtr(), packet = std::move(packet) ] { + if (engine.get()) engine->DispatchPointerDataPacket(*packet); - } })); } @@ -614,11 +573,13 @@ - (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { #pragma mark - Handle view resizing - (void)updateViewportMetrics { - _shell->GetTaskRunners().GetUITaskRunner()->PostTask( - [engine = _shell->GetEngine(), metrics = _viewportMetrics]() { - if (engine) { - engine->SetViewportMetrics(std::move(metrics)); + blink::Threads::UI()->PostTask( + [ weak_platform_view = _platformView->GetWeakPtr(), metrics = _viewportMetrics ] { + if (!weak_platform_view) { + return; } + weak_platform_view->UpdateSurfaceSize(); + weak_platform_view->engine().SetViewportMetrics(metrics); }); } @@ -748,7 +709,7 @@ - (void)onVoiceOverChanged:(NSNotification*)notification { #else bool enabled = UIAccessibilityIsVoiceOverRunning(); #endif - _shell->GetPlatformView()->SetSemanticsEnabled(enabled); + _platformView->ToggleAccessibility(self.view, enabled); } #pragma mark - Memory Notifications @@ -914,50 +875,46 @@ - (void)sendOnChannel:(NSString*)channel message:(NSData*)message binaryReply:(FlutterBinaryReply)callback { NSAssert(channel, @"The channel must not be null"); - fxl::RefPtr response = + fxl::RefPtr response = (callback == nil) ? nullptr - : fxl::MakeRefCounted( - ^(NSData* reply) { - callback(reply); - }, - _shell->GetTaskRunners().GetPlatformTaskRunner()); + : fxl::MakeRefCounted(^(NSData* reply) { + callback(reply); + }); fxl::RefPtr platformMessage = (message == nil) ? fxl::MakeRefCounted(channel.UTF8String, response) : fxl::MakeRefCounted( channel.UTF8String, shell::GetVectorFromNSData(message), response); - - _shell->GetPlatformView()->DispatchPlatformMessage(platformMessage); + _platformView->DispatchPlatformMessage(platformMessage); } - (void)setMessageHandlerOnChannel:(NSString*)channel binaryMessageHandler:(FlutterBinaryMessageHandler)handler { NSAssert(channel, @"The channel must not be null"); - [self iosPlatformView] -> GetPlatformMessageRouter().SetMessageHandler(channel.UTF8String, - handler); + _platformView->platform_message_router().SetMessageHandler(channel.UTF8String, handler); } #pragma mark - FlutterTextureRegistry - (int64_t)registerTexture:(NSObject*)texture { int64_t textureId = _nextTextureId++; - [self iosPlatformView] -> RegisterExternalTexture(textureId, texture); + _platformView->RegisterExternalTexture(textureId, texture); return textureId; } - (void)unregisterTexture:(int64_t)textureId { - _shell->GetPlatformView()->UnregisterTexture(textureId); + _platformView->UnregisterTexture(textureId); } - (void)textureFrameAvailable:(int64_t)textureId { - _shell->GetPlatformView()->MarkTextureFrameAvailable(textureId); + _platformView->MarkTextureFrameAvailable(textureId); } - (NSString*)lookupKeyForAsset:(NSString*)asset { - return [FlutterDartProject lookupKeyForAsset:asset]; + return [FlutterDartProject lookupKeyForAsset:asset]; } - (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package { - return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package]; + return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package]; } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h deleted file mode 100644 index 482379c8f17eb..0000000000000 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2017 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_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_ - -#include "flutter/shell/common/shell.h" -#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" - -@interface FlutterViewController () - -- (shell::Shell&)shell; - -@end - -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERVIEWCONTROLLER_INTERNAL_H_ diff --git a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm index 6a545b95e4276..3f96f37a9c2db 100644 --- a/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm +++ b/shell/platform/darwin/ios/framework/Source/accessibility_bridge.mm @@ -427,7 +427,7 @@ - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction { weak_factory_(this) { accessibility_channel_.reset([[FlutterBasicMessageChannel alloc] initWithName:@"flutter/accessibility" - binaryMessenger:platform_view->GetOwnerViewController() + binaryMessenger:platform_view->binary_messenger() codec:[FlutterStandardMessageCodec sharedInstance]]); [accessibility_channel_.get() setMessageHandler:^(id message, FlutterReply reply) { HandleEvent((NSDictionary*)message); @@ -440,7 +440,7 @@ - (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction { } UIView* AccessibilityBridge::textInputView() { - return [platform_view_->GetTextInputPlugin() textInputView]; + return [platform_view_->text_input_plugin() textInputView]; } void AccessibilityBridge::UpdateSemantics(blink::SemanticsNodeUpdates nodes) { diff --git a/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h b/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h new file mode 100644 index 0000000000000..f2e54dd2c2806 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h @@ -0,0 +1,18 @@ +// Copyright 2017 The Chromium 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_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTER_MAIN_IOS_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTER_MAIN_IOS_H_ + +#include "lib/fxl/macros.h" + +namespace shell { + +/// Initializes the Flutter shell. This must be called before interacting with +/// the engine in any way. It is safe to call this method multiple times. +void FlutterMain(); + +} // namespace shell + +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTER_MAIN_IOS_H_ diff --git a/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm b/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm new file mode 100644 index 0000000000000..aa7ad5fd85727 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm @@ -0,0 +1,25 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h" + +#include "flutter/shell/platform/darwin/common/platform_mac.h" +#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" + +namespace shell { + +void FlutterMain() { + NSBundle* bundle = [NSBundle bundleForClass:[FlutterViewController class]]; + NSString* icuDataPath = [bundle pathForResource:@"icudtl" ofType:@"dat"]; + NSString* libraryName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FLTLibraryPath"]; + + NSBundle* mainBundle = [NSBundle mainBundle]; + NSString* flutterAssetsPath = [FlutterDartProject pathForFlutterAssetsFromBundle:mainBundle]; + + shell::PlatformMacMain(icuDataPath.UTF8String, libraryName != nil ? libraryName.UTF8String : "", + flutterAssetsPath.UTF8String); +} + +} // namespace shell diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h deleted file mode 100644 index b861c5036e97d..0000000000000 --- a/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2018 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_DARWIN_IOS_FRAMEWORK_SOURCE_PLATFORM_MESSAGE_RESPONSE_DARWIN_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_PLATFORM_MESSAGE_RESPONSE_DARWIN_H_ - -#include - -#include "flutter/fml/platform/darwin/scoped_block.h" -#include "flutter/fml/task_runner.h" -#include "flutter/lib/ui/window/platform_message_response.h" -#include "flutter/shell/platform/darwin/common/buffer_conversions.h" -#include "lib/fxl/functional/make_copyable.h" -#include "lib/fxl/macros.h" - -typedef void (^PlatformMessageResponseCallback)(NSData*); - -namespace shell { - -class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { - public: - void Complete(std::vector data) override { - fxl::RefPtr self(this); - platform_task_runner_->PostTask(fxl::MakeCopyable([self, data = std::move(data)]() mutable { - self->callback_.get()(shell::GetNSDataFromVector(data)); - })); - } - - void CompleteEmpty() override { - fxl::RefPtr self(this); - platform_task_runner_->PostTask( - fxl::MakeCopyable([self]() mutable { self->callback_.get()(nil); })); - } - - private: - explicit PlatformMessageResponseDarwin(PlatformMessageResponseCallback callback, - fxl::RefPtr platform_task_runner) - : callback_(callback, fml::OwnershipPolicy::Retain), - platform_task_runner_(std::move(platform_task_runner)) {} - - fml::ScopedBlock callback_; - fxl::RefPtr platform_task_runner_; - - FRIEND_MAKE_REF_COUNTED(PlatformMessageResponseDarwin); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_PLATFORM_MESSAGE_RESPONSE_DARWIN_H_ diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm deleted file mode 100644 index 8590b4e36942b..0000000000000 --- a/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2018 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. - -#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h" - -namespace shell { - -// - -} // namespace shell diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_router.h b/shell/platform/darwin/ios/framework/Source/platform_message_router.h index d2488f82fe47c..cfa91c04771c3 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_message_router.h +++ b/shell/platform/darwin/ios/framework/Source/platform_message_router.h @@ -7,7 +7,6 @@ #include -#include "flutter/fml/platform/darwin/scoped_block.h" #include "flutter/lib/ui/window/platform_message.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterBinaryMessenger.h" #include "lib/fxl/memory/weak_ptr.h" @@ -19,13 +18,13 @@ class PlatformMessageRouter { PlatformMessageRouter(); ~PlatformMessageRouter(); - void HandlePlatformMessage(fxl::RefPtr message) const; + void HandlePlatformMessage(fxl::RefPtr message); void SetMessageHandler(const std::string& channel, FlutterBinaryMessageHandler handler); private: - std::unordered_map> + std::unordered_map message_handlers_; FXL_DISALLOW_COPY_AND_ASSIGN(PlatformMessageRouter); diff --git a/shell/platform/darwin/ios/framework/Source/platform_message_router.mm b/shell/platform/darwin/ios/framework/Source/platform_message_router.mm index 3ab75bff522f8..70625143b623e 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_message_router.mm +++ b/shell/platform/darwin/ios/framework/Source/platform_message_router.mm @@ -14,8 +14,7 @@ PlatformMessageRouter::~PlatformMessageRouter() = default; -void PlatformMessageRouter::HandlePlatformMessage( - fxl::RefPtr message) const { +void PlatformMessageRouter::HandlePlatformMessage(fxl::RefPtr message) { fxl::RefPtr completer = message->response(); auto it = message_handlers_.find(message->channel()); if (it != message_handlers_.end()) { @@ -42,10 +41,14 @@ void PlatformMessageRouter::SetMessageHandler(const std::string& channel, FlutterBinaryMessageHandler handler) { - message_handlers_.erase(channel); - if (handler) { - message_handlers_[channel] = - fml::ScopedBlock{handler, fml::OwnershipPolicy::Retain}; + if (handler) + message_handlers_[channel] = [handler copy]; + else { + auto it = message_handlers_.find(channel); + if (it != message_handlers_.end()) { + [it->second release]; + message_handlers_.erase(it); + } } } diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h index 23aaf02510d6d..6a3362b215667 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h @@ -5,26 +5,27 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_VSYNC_WAITER_IOS_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_VSYNC_WAITER_IOS_H_ -#include "flutter/fml/memory/weak_ptr.h" -#include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/vsync_waiter.h" #include "lib/fxl/macros.h" +#if __OBJC__ @class VSyncClient; +#else // __OBJC__ +class VSyncClient; +#endif // __OBJC__ namespace shell { -class VsyncWaiterIOS final : public VsyncWaiter { +class VsyncWaiterIOS : public VsyncWaiter { public: - VsyncWaiterIOS(blink::TaskRunners task_runners); - + VsyncWaiterIOS(); ~VsyncWaiterIOS() override; - private: - fml::scoped_nsobject client_; + void AsyncWaitForVsync(Callback callback) override; - // |shell::VsyncWaiter| - void AwaitVSync() override; + private: + Callback callback_; + VSyncClient* client_; FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterIOS); }; diff --git a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm index 4589368acd3fb..78d6678189123 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm @@ -10,62 +10,29 @@ #include #include -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/glue/trace_event.h" #include "lib/fxl/logging.h" @interface VSyncClient : NSObject -- (instancetype)initWithTaskRunner:(fxl::RefPtr)task_runner - callback:(shell::VsyncWaiter::Callback)callback; - -- (void)await; - -- (void)invalidate; - @end -namespace shell { - -VsyncWaiterIOS::VsyncWaiterIOS(blink::TaskRunners task_runners) - : VsyncWaiter(std::move(task_runners)), - client_([[VSyncClient alloc] initWithTaskRunner:task_runners_.GetUITaskRunner() - callback:std::bind(&VsyncWaiterIOS::FireCallback, - this, - std::placeholders::_1, - std::placeholders::_2)]) {} - -VsyncWaiterIOS::~VsyncWaiterIOS() { - // This way, we will get no more callbacks from the display link that holds a weak (non-nilling) - // reference to this C++ object. - [client_.get() invalidate]; -} - -void VsyncWaiterIOS::AwaitVSync() { - [client_.get() await]; -} - -} // namespace shell - @implementation VSyncClient { - shell::VsyncWaiter::Callback callback_; - fml::scoped_nsobject display_link_; + CADisplayLink* _displayLink; + shell::VsyncWaiter::Callback _pendingCallback; } -- (instancetype)initWithTaskRunner:(fxl::RefPtr)task_runner - callback:(shell::VsyncWaiter::Callback)callback { +- (instancetype)init { self = [super init]; if (self) { - callback_ = std::move(callback); - display_link_ = fml::scoped_nsobject { - [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain] - }; - display_link_.get().paused = YES; - - task_runner->PostTask([client = [self retain]]() { - [client->display_link_.get() addToRunLoop:[NSRunLoop currentRunLoop] - forMode:NSRunLoopCommonModes]; + _displayLink = + [[CADisplayLink displayLinkWithTarget:self selector:@selector(onDisplayLink:)] retain]; + _displayLink.paused = YES; + + blink::Threads::UI()->PostTask([client = [self retain]]() { + [client->_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; [client release]; }); } @@ -73,28 +40,68 @@ - (instancetype)initWithTaskRunner:(fxl::RefPtr)task_runner return self; } -- (void)await { - display_link_.get().paused = NO; +- (void)await:(shell::VsyncWaiter::Callback)callback { + FXL_DCHECK(!_pendingCallback); + _pendingCallback = std::move(callback); + _displayLink.paused = NO; } - (void)onDisplayLink:(CADisplayLink*)link { fxl::TimePoint frame_start_time = fxl::TimePoint::Now(); fxl::TimePoint frame_target_time = frame_start_time + fxl::TimeDelta::FromSecondsF(link.duration); - display_link_.get().paused = YES; - - callback_(frame_start_time, frame_target_time); -} - -- (void)invalidate { - // [CADisplayLink invalidate] is thread-safe. - [display_link_.get() invalidate]; + _displayLink.paused = YES; + + // Note: The tag name must be "VSYNC" (it is special) so that the "Highlight + // Vsync" checkbox in the timeline can be enabled. + // See: https://github.com/catapult-project/catapult/blob/2091404475cbba9b786 + // 442979b6ec631305275a6/tracing/tracing/extras/vsync/vsync_auditor.html#L26 +#if FLUTTER_RUNTIME_MODE == FLUTTER_RUNTIME_MODE_RELEASE + TRACE_EVENT1("flutter", "VSYNC", "mode", "basic"); +#else + { + fxl::TimeDelta delta = frame_target_time.ToEpochDelta(); + constexpr size_t num_chars = sizeof(int64_t) * CHAR_BIT * 3.4 + 2; + char deadline[num_chars]; + sprintf(deadline, "%lld", delta.ToMicroseconds()); + TRACE_EVENT2("flutter", "VSYNC", "mode", "basic", "deadline", deadline); + } +#endif + + // Note: Even though we know we are on the UI thread already (since the + // display link was scheduled on the UI thread in the contructor), we use + // the PostTask mechanism because the callback may have side-effects that need + // to be addressed via a task observer. Invoking the callback by itself + // bypasses such task observers. + // + // We are not using the PostTask for thread switching, but to make task + // observers work. + blink::Threads::UI()->PostTask([ + callback = _pendingCallback, frame_start_time, frame_target_time + ]() { callback(frame_start_time, frame_target_time); }); + + _pendingCallback = nullptr; } - (void)dealloc { - [self invalidate]; + [_displayLink invalidate]; + [_displayLink release]; [super dealloc]; } @end + +namespace shell { + +VsyncWaiterIOS::VsyncWaiterIOS() : client_([[VSyncClient alloc] init]) {} + +VsyncWaiterIOS::~VsyncWaiterIOS() { + [client_ release]; +} + +void VsyncWaiterIOS::AsyncWaitForVsync(Callback callback) { + [client_ await:callback]; +} + +} // namespace shell diff --git a/shell/platform/darwin/ios/ios_external_texture_gl.h b/shell/platform/darwin/ios/ios_external_texture_gl.h index baedf298bd61d..a658fdf31628a 100644 --- a/shell/platform/darwin/ios/ios_external_texture_gl.h +++ b/shell/platform/darwin/ios/ios_external_texture_gl.h @@ -25,8 +25,6 @@ class IOSExternalTextureGL : public flow::Texture { virtual void OnGrContextDestroyed() override; - virtual void MarkNewFrameAvailable() override; - private: NSObject* external_texture_; fml::CFRef cache_ref_; diff --git a/shell/platform/darwin/ios/ios_external_texture_gl.mm b/shell/platform/darwin/ios/ios_external_texture_gl.mm index 0bd9a8ca3c7cb..2cc9721e7f09a 100644 --- a/shell/platform/darwin/ios/ios_external_texture_gl.mm +++ b/shell/platform/darwin/ios/ios_external_texture_gl.mm @@ -4,10 +4,11 @@ #include "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h" -#import +#include #import #import - +#include "flutter/common/threads.h" +#include "flutter/lib/ui/painting/resource_context.h" #include "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h" #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/GrBackendSurface.h" @@ -25,6 +26,7 @@ IOSExternalTextureGL::~IOSExternalTextureGL() = default; void IOSExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds) { + ASSERT_IS_GPU_THREAD; if (!cache_ref_) { CVOpenGLESTextureCacheRef cache; CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, @@ -55,8 +57,10 @@ return; } GrGLTextureInfo textureInfo = {CVOpenGLESTextureGetTarget(texture_ref_), - CVOpenGLESTextureGetName(texture_ref_), GL_RGBA8_OES}; - GrBackendTexture backendTexture(bounds.width(), bounds.height(), GrMipMapped::kNo, textureInfo); + CVOpenGLESTextureGetName(texture_ref_), + GL_RGBA8_OES}; + GrBackendTexture backendTexture(bounds.width(), bounds.height(), GrMipMapped::kNo, + textureInfo); sk_sp image = SkImage::MakeFromTexture(canvas.getGrContext(), backendTexture, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); @@ -65,13 +69,14 @@ } } -void IOSExternalTextureGL::OnGrContextCreated() {} +void IOSExternalTextureGL::OnGrContextCreated() { + ASSERT_IS_GPU_THREAD +} void IOSExternalTextureGL::OnGrContextDestroyed() { + ASSERT_IS_GPU_THREAD texture_ref_.Reset(nullptr); cache_ref_.Reset(nullptr); } -void IOSExternalTextureGL::MarkNewFrameAvailable() {} - } // namespace shell diff --git a/shell/platform/darwin/ios/ios_gl_context.h b/shell/platform/darwin/ios/ios_gl_context.h index f42c1436461b1..89ad7e0347eac 100644 --- a/shell/platform/darwin/ios/ios_gl_context.h +++ b/shell/platform/darwin/ios/ios_gl_context.h @@ -18,7 +18,7 @@ namespace shell { class IOSGLContext { public: - IOSGLContext(fml::scoped_nsobject layer); + IOSGLContext(PlatformView::SurfaceConfig config, CAEAGLLayer* layer); ~IOSGLContext(); diff --git a/shell/platform/darwin/ios/ios_gl_context.mm b/shell/platform/darwin/ios/ios_gl_context.mm index 77a124e64a291..de94018d0689e 100644 --- a/shell/platform/darwin/ios/ios_gl_context.mm +++ b/shell/platform/darwin/ios/ios_gl_context.mm @@ -3,17 +3,21 @@ // found in the LICENSE file. #include "flutter/shell/platform/darwin/ios/ios_gl_context.h" - -#include - -#include "flutter/fml/trace_event.h" #include "third_party/skia/include/gpu/GrContextOptions.h" #include "third_party/skia/include/gpu/gl/GrGLInterface.h" +#include + namespace shell { -IOSGLContext::IOSGLContext(fml::scoped_nsobject layer) - : layer_(std::move(layer)), +#define VERIFY(x) \ + if (!(x)) { \ + FXL_DLOG(ERROR) << "Failed: " #x; \ + return; \ + }; + +IOSGLContext::IOSGLContext(PlatformView::SurfaceConfig config, CAEAGLLayer* layer) + : layer_([layer retain]), context_([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]), resource_context_([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:context_.get().sharegroup]), @@ -22,34 +26,34 @@ storage_size_width_(0), storage_size_height_(0), valid_(false) { - FXL_DCHECK(layer_ != nullptr); - FXL_DCHECK(context_ != nullptr); - FXL_DCHECK(resource_context_ != nullptr); + VERIFY(layer_ != nullptr); + VERIFY(context_ != nullptr); + VERIFY(resource_context_ != nullptr); bool context_current = [EAGLContext setCurrentContext:context_]; - FXL_DCHECK(context_current); - FXL_DCHECK(glGetError() == GL_NO_ERROR); + VERIFY(context_current); + VERIFY(glGetError() == GL_NO_ERROR); // Generate the framebuffer glGenFramebuffers(1, &framebuffer_); - FXL_DCHECK(glGetError() == GL_NO_ERROR); - FXL_DCHECK(framebuffer_ != GL_NONE); + VERIFY(glGetError() == GL_NO_ERROR); + VERIFY(framebuffer_ != GL_NONE); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_); - FXL_DCHECK(glGetError() == GL_NO_ERROR); + VERIFY(glGetError() == GL_NO_ERROR); // Setup color attachment glGenRenderbuffers(1, &colorbuffer_); - FXL_DCHECK(colorbuffer_ != GL_NONE); + VERIFY(colorbuffer_ != GL_NONE); glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_); - FXL_DCHECK(glGetError() == GL_NO_ERROR); + VERIFY(glGetError() == GL_NO_ERROR); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer_); - FXL_DCHECK(glGetError() == GL_NO_ERROR); + VERIFY(glGetError() == GL_NO_ERROR); // TODO: // iOS displays are more variable than just P3 or sRGB. Reading the display @@ -135,12 +139,24 @@ return false; } - // Fetch the dimensions of the color buffer whose backing was just updated. - glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &storage_size_width_); - FXL_DCHECK(glGetError() == GL_NO_ERROR); + GLint width = 0; + GLint height = 0; - glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &storage_size_height_); - FXL_DCHECK(glGetError() == GL_NO_ERROR); + if (colorbuffer_ != GL_NONE) { + // Fetch the dimensions of the color buffer whose backing was just updated + // so that backing of the attachments can be updated + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width); + FXL_DCHECK(glGetError() == GL_NO_ERROR); + + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height); + FXL_DCHECK(glGetError() == GL_NO_ERROR); + + glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_); + FXL_DCHECK(glGetError() == GL_NO_ERROR); + } + + storage_size_width_ = width; + storage_size_height_ = height; FXL_DCHECK(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); diff --git a/shell/platform/darwin/ios/ios_surface.h b/shell/platform/darwin/ios/ios_surface.h index b629c2709e3d1..c164fab15500e 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -5,17 +5,25 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_H_ -#include - #include "flutter/fml/platform/darwin/scoped_nsobject.h" -#include "flutter/shell/common/surface.h" +#include "flutter/shell/common/platform_view.h" #include "lib/fxl/macros.h" +@class CALayer; + namespace shell { class IOSSurface { public: - IOSSurface(); + static std::unique_ptr Create( + PlatformView::SurfaceConfig surface_config, + CALayer* layer); + + IOSSurface(PlatformView::SurfaceConfig surface_config, CALayer* layer); + + CALayer* GetLayer() const; + + PlatformView::SurfaceConfig GetSurfaceConfig() const; virtual ~IOSSurface(); @@ -28,6 +36,9 @@ class IOSSurface { virtual std::unique_ptr CreateGPUSurface() = 0; public: + PlatformView::SurfaceConfig surface_config_; + fml::scoped_nsobject layer_; + FXL_DISALLOW_COPY_AND_ASSIGN(IOSSurface); }; diff --git a/shell/platform/darwin/ios/ios_surface.mm b/shell/platform/darwin/ios/ios_surface.mm index b0b9cc3245183..91067838330f6 100644 --- a/shell/platform/darwin/ios/ios_surface.mm +++ b/shell/platform/darwin/ios/ios_surface.mm @@ -4,15 +4,40 @@ #include "flutter/shell/platform/darwin/ios/ios_surface.h" -#include - #include #include +#include + +@class CALayer; +@class CAEAGLLayer; namespace shell { -IOSSurface::IOSSurface() = default; +std::unique_ptr IOSSurface::Create(PlatformView::SurfaceConfig surface_config, + CALayer* layer) { + // Check if we can use OpenGL. + if ([layer isKindOfClass:[CAEAGLLayer class]]) { + return std::make_unique(surface_config, reinterpret_cast(layer)); + } + + // If we ever support the metal rendering API, a check for CAMetalLayer would + // go here. + + // Finally, fallback to software rendering. + return std::make_unique(surface_config, layer); +} + +IOSSurface::IOSSurface(PlatformView::SurfaceConfig surface_config, CALayer* layer) + : surface_config_(surface_config), layer_([layer retain]) {} IOSSurface::~IOSSurface() = default; +CALayer* IOSSurface::GetLayer() const { + return layer_; +} + +PlatformView::SurfaceConfig IOSSurface::GetSurfaceConfig() const { + return surface_config_; +} + } // namespace shell diff --git a/shell/platform/darwin/ios/ios_surface_gl.h b/shell/platform/darwin/ios/ios_surface_gl.h index 7486d343eb0fd..f7e43e2588984 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -5,7 +5,6 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_GL_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_GL_H_ -#include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/gpu/gpu_surface_gl.h" #include "flutter/shell/platform/darwin/ios/ios_gl_context.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" @@ -17,7 +16,7 @@ namespace shell { class IOSSurfaceGL : public IOSSurface, public GPUSurfaceGLDelegate { public: - IOSSurfaceGL(fml::scoped_nsobject layer); + IOSSurfaceGL(PlatformView::SurfaceConfig surface_config, CAEAGLLayer* layer); ~IOSSurfaceGL() override; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index 253531c4800aa..60756d6094fc9 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -4,12 +4,13 @@ #include "flutter/shell/platform/darwin/ios/ios_surface_gl.h" -#include "flutter/fml/trace_event.h" #include "flutter/shell/gpu/gpu_surface_gl.h" namespace shell { -IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer) : context_(std::move(layer)) {} +IOSSurfaceGL::IOSSurfaceGL(PlatformView::SurfaceConfig surface_config, CAEAGLLayer* layer) + : IOSSurface(surface_config, reinterpret_cast(layer)), + context_(surface_config, layer) {} IOSSurfaceGL::~IOSSurfaceGL() = default; diff --git a/shell/platform/darwin/ios/ios_surface_software.h b/shell/platform/darwin/ios/ios_surface_software.h index e8fc332f06c8c..7e3f264b28ce6 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -5,19 +5,17 @@ #ifndef FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_SOFTWARE_H_ #define FLUTTER_SHELL_PLATFORM_DARWIN_IOS_IOS_SURFACE_SOFTWARE_H_ -#include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/gpu/gpu_surface_software.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" #include "lib/fxl/macros.h" -@class CALayer; - namespace shell { -class IOSSurfaceSoftware final : public IOSSurface, - public GPUSurfaceSoftwareDelegate { +class IOSSurfaceSoftware : public IOSSurface, + public GPUSurfaceSoftwareDelegate { public: - IOSSurfaceSoftware(fml::scoped_nsobject layer); + IOSSurfaceSoftware(PlatformView::SurfaceConfig surface_config, + CALayer* layer); ~IOSSurfaceSoftware() override; @@ -34,7 +32,6 @@ class IOSSurfaceSoftware final : public IOSSurface, bool PresentBackingStore(sk_sp backing_store) override; private: - fml::scoped_nsobject layer_; sk_sp sk_surface_; FXL_DISALLOW_COPY_AND_ASSIGN(IOSSurfaceSoftware); diff --git a/shell/platform/darwin/ios/ios_surface_software.mm b/shell/platform/darwin/ios/ios_surface_software.mm index b09a5d9a2d8a3..9a4e90e45dfba 100644 --- a/shell/platform/darwin/ios/ios_surface_software.mm +++ b/shell/platform/darwin/ios/ios_surface_software.mm @@ -15,15 +15,15 @@ namespace shell { -IOSSurfaceSoftware::IOSSurfaceSoftware(fml::scoped_nsobject layer) - : layer_(std::move(layer)) { +IOSSurfaceSoftware::IOSSurfaceSoftware(PlatformView::SurfaceConfig surface_config, CALayer* layer) + : IOSSurface(surface_config, layer) { UpdateStorageSizeIfNecessary(); } IOSSurfaceSoftware::~IOSSurfaceSoftware() = default; bool IOSSurfaceSoftware::IsValid() const { - return layer_; + return GetLayer() != nullptr; } bool IOSSurfaceSoftware::ResourceContextMakeCurrent() { @@ -120,7 +120,8 @@ return false; } - layer_.get().contents = reinterpret_cast(static_cast(pixmap_image)); + CALayer* layer = GetLayer(); + layer.contents = reinterpret_cast(static_cast(pixmap_image)); return true; } diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index e7849dda44641..dab19a0f9ce1a 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -8,66 +8,95 @@ #include #include "flutter/fml/memory/weak_ptr.h" -#include "flutter/fml/platform/darwin/scoped_nsobject.h" #include "flutter/shell/common/platform_view.h" #include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterTexture.h" -#include "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputPlugin.h" #include "flutter/shell/platform/darwin/ios/framework/Source/accessibility_bridge.h" #include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_router.h" #include "flutter/shell/platform/darwin/ios/ios_surface.h" #include "lib/fxl/functional/closure.h" #include "lib/fxl/macros.h" +@class CALayer; +@class UIView; + namespace shell { -class PlatformViewIOS final : public PlatformView { +class PlatformViewIOS : public PlatformView { public: - explicit PlatformViewIOS(PlatformView::Delegate& delegate, - blink::TaskRunners task_runners, - FlutterViewController* owner_controller_, - FlutterView* owner_view_); + explicit PlatformViewIOS(CALayer* layer, + NSObject* binaryMessenger); ~PlatformViewIOS() override; - PlatformMessageRouter& GetPlatformMessageRouter(); + void Attach() override; - FlutterViewController* GetOwnerViewController() const; + void Attach(fxl::Closure firstFrameCallback); - void RegisterExternalTexture(int64_t id, NSObject* texture); + void NotifyCreated(); - fml::scoped_nsprotocol GetTextInputPlugin() const; + void ToggleAccessibility(UIView* view, bool enabled); - void SetTextInputPlugin( - fml::scoped_nsprotocol plugin); + PlatformMessageRouter& platform_message_router() { + return platform_message_router_; + } - private: - FlutterViewController* owner_controller_; // weak reference. - FlutterView* owner_view_; // weak reference. - std::unique_ptr ios_surface_; - PlatformMessageRouter platform_message_router_; - std::unique_ptr accessibility_bridge_; - fml::scoped_nsprotocol text_input_plugin_; - fxl::Closure firstFrameCallback_; + fml::WeakPtr GetWeakPtr(); - // |shell::PlatformView| - std::unique_ptr CreateRenderingSurface() override; + void UpdateSurfaceSize(); - // |shell::PlatformView| - sk_sp CreateResourceContext() const override; + VsyncWaiter* GetVsyncWaiter() override; - // |shell::PlatformView| - void SetSemanticsEnabled(bool enabled) override; + bool ResourceContextMakeCurrent() override; - // |shell::PlatformView| void HandlePlatformMessage( fxl::RefPtr message) override; - // |shell::PlatformView| + void RegisterExternalTexture(int64_t id, NSObject* texture); + void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - // |shell::PlatformView| - std::unique_ptr CreateVSyncWaiter() override; + void RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) override; + + void SetAssetBundlePath(const std::string& assets_directory) override; + + /** + * Exposes the `FlutterTextInputPlugin` singleton for the + * `AccessibilityBridge` to be able to interact with the text entry system. + */ + fml::scoped_nsprotocol text_input_plugin() { + return text_input_plugin_; + } + + /** + * Sets the `FlutterTextInputPlugin` singleton returned by + * `text_input_plugin`. + */ + void SetTextInputPlugin( + fml::scoped_nsprotocol textInputPlugin) { + text_input_plugin_ = textInputPlugin; + } + + NSObject* binary_messenger() const { + return binary_messenger_; + } + + private: + std::unique_ptr ios_surface_; + PlatformMessageRouter platform_message_router_; + std::unique_ptr accessibility_bridge_; + fxl::Closure firstFrameCallback_; + fml::WeakPtrFactory weak_factory_; + NSObject* binary_messenger_; + fml::scoped_nsprotocol text_input_plugin_; + + void SetupAndLoadFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages); + + void SetAssetBundlePathOnUI(const std::string& assets_directory); FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewIOS); }; diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index 1fba8e5e026e5..19c5dd4e663a1 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -8,92 +8,135 @@ #include -#include "flutter/common/task_runners.h" +#include "flutter/common/threads.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/common/io_manager.h" +#include "flutter/shell/gpu/gpu_rasterizer.h" +#include "flutter/shell/platform/darwin/common/process_info_mac.h" #include "flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h" #include "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h" #include "lib/fxl/synchronization/waitable_event.h" namespace shell { -PlatformViewIOS::PlatformViewIOS(PlatformView::Delegate& delegate, - blink::TaskRunners task_runners, - FlutterViewController* owner_controller, - FlutterView* owner_view) - : PlatformView(delegate, std::move(task_runners)), - owner_controller_(owner_controller), - owner_view_(owner_view), - ios_surface_(owner_view_.createSurface) { - FXL_DCHECK(ios_surface_ != nullptr); - FXL_DCHECK(owner_controller_ != nullptr); - FXL_DCHECK(owner_view_ != nullptr); -} +PlatformViewIOS::PlatformViewIOS(CALayer* layer, NSObject* binaryMessenger) + : PlatformView(std::make_unique(std::make_unique())), + ios_surface_(IOSSurface::Create(surface_config_, layer)), + weak_factory_(this), + binary_messenger_(binaryMessenger) {} PlatformViewIOS::~PlatformViewIOS() = default; -FlutterViewController* PlatformViewIOS::GetOwnerViewController() const { - return owner_controller_; +void PlatformViewIOS::Attach() { + Attach(NULL); } -PlatformMessageRouter& PlatformViewIOS::GetPlatformMessageRouter() { - return platform_message_router_; +void PlatformViewIOS::Attach(fxl::Closure firstFrameCallback) { + CreateEngine(); + + if (firstFrameCallback) { + firstFrameCallback_ = firstFrameCallback; + rasterizer_->AddNextFrameCallback([weakSelf = GetWeakPtr()] { + if (weakSelf) { + weakSelf->firstFrameCallback_(); + weakSelf->firstFrameCallback_ = nullptr; + } + }); + } } -void PlatformViewIOS::RegisterExternalTexture(int64_t texture_id, - NSObject* texture) { - RegisterTexture(std::make_shared(texture_id, texture)); +void PlatformViewIOS::NotifyCreated() { + PlatformView::NotifyCreated(ios_surface_->CreateGPUSurface()); +} + +void PlatformViewIOS::ToggleAccessibility(UIView* view, bool enabled) { + if (enabled) { + if (!accessibility_bridge_) { + accessibility_bridge_.reset(new shell::AccessibilityBridge(view, this)); + } + } else { + accessibility_bridge_ = nullptr; + } + SetSemanticsEnabled(enabled); } -// |shell::PlatformView| -std::unique_ptr PlatformViewIOS::CreateRenderingSurface() { - return ios_surface_->CreateGPUSurface(); +void PlatformViewIOS::SetupAndLoadFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) { + blink::Threads::UI()->PostTask( + [ engine = engine().GetWeakPtr(), assets_directory, main, packages ] { + if (engine) + engine->RunBundleAndSource(assets_directory, main, packages); + }); } -// |shell::PlatformView| -sk_sp PlatformViewIOS::CreateResourceContext() const { - if (!ios_surface_->ResourceContextMakeCurrent()) { - FXL_DLOG(INFO) << "Could not make resource context current on IO thread. Async texture uploads " - "will be disabled."; - return nullptr; - } +void PlatformViewIOS::SetAssetBundlePathOnUI(const std::string& assets_directory) { + blink::Threads::UI()->PostTask([ engine = engine().GetWeakPtr(), assets_directory ] { + if (engine) + engine->SetAssetBundlePath(assets_directory); + }); +} - return IOManager::CreateCompatibleResourceLoadingContext(GrBackend::kOpenGL_GrBackend); +fml::WeakPtr PlatformViewIOS::GetWeakPtr() { + return weak_factory_.GetWeakPtr(); } -// |shell::PlatformView| -void PlatformViewIOS::SetSemanticsEnabled(bool enabled) { - if (enabled && !accessibility_bridge_) { - accessibility_bridge_ = std::make_unique(owner_view_, this); - } else { - accessibility_bridge_.reset(); +void PlatformViewIOS::UpdateSurfaceSize() { + blink::Threads::Gpu()->PostTask([self = GetWeakPtr()]() { + if (self && self->ios_surface_ != nullptr) { + self->ios_surface_->UpdateStorageSizeIfNecessary(); + } + }); +} + +VsyncWaiter* PlatformViewIOS::GetVsyncWaiter() { + if (!vsync_waiter_) { + vsync_waiter_ = std::make_unique(); } - PlatformView::SetSemanticsEnabled(enabled); + return vsync_waiter_.get(); +} + +bool PlatformViewIOS::ResourceContextMakeCurrent() { + return ios_surface_ != nullptr ? ios_surface_->ResourceContextMakeCurrent() : false; } -// |shell::PlatformView| void PlatformViewIOS::UpdateSemantics(blink::SemanticsNodeUpdates update) { - if (accessibility_bridge_) { + if (accessibility_bridge_) accessibility_bridge_->UpdateSemantics(std::move(update)); - } } -// |shell::PlatformView| void PlatformViewIOS::HandlePlatformMessage(fxl::RefPtr message) { platform_message_router_.HandlePlatformMessage(std::move(message)); } -// |shell::PlatformView| -std::unique_ptr PlatformViewIOS::CreateVSyncWaiter() { - return std::make_unique(task_runners_); +void PlatformViewIOS::RegisterExternalTexture(int64_t texture_id, + NSObject* texture) { + RegisterTexture(std::make_shared(texture_id, texture)); } -fml::scoped_nsprotocol PlatformViewIOS::GetTextInputPlugin() const { - return text_input_plugin_; +void PlatformViewIOS::RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) { + auto latch = new fxl::ManualResetWaitableEvent(); + + dispatch_async(dispatch_get_main_queue(), ^{ + SetupAndLoadFromSource(assets_directory, main, packages); + latch->Signal(); + }); + + latch->Wait(); + delete latch; } -void PlatformViewIOS::SetTextInputPlugin(fml::scoped_nsprotocol plugin) { - text_input_plugin_ = plugin; +void PlatformViewIOS::SetAssetBundlePath(const std::string& assets_directory) { + auto latch = new fxl::ManualResetWaitableEvent(); + + dispatch_async(dispatch_get_main_queue(), ^{ + SetAssetBundlePathOnUI(assets_directory); + latch->Signal(); + }); + + latch->Wait(); + delete latch; } } // namespace shell diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index b1e0b3e4f3b71..7ce6f7e8d5be1 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -4,21 +4,16 @@ import("$flutter_root/testing/testing.gni") -static_library("embedder") { - complete_static_lib = true - +source_set("embedder") { sources = [ "embedder.cc", "embedder.h", - "embedder_engine.cc", - "embedder_engine.h", "embedder_include.c", "platform_view_embedder.cc", "platform_view_embedder.h", ] deps = [ - "$flutter_root/assets", "$flutter_root/common", "$flutter_root/fml", "$flutter_root/shell/common", @@ -27,7 +22,6 @@ static_library("embedder") { "//third_party/dart/runtime:libdart_jit", "//third_party/dart/runtime/bin:embedded_dart_io", "//third_party/skia", - "//third_party/skia:gpu", "//topaz/lib/tonic", ] diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index a7ee807934663..866413cbc077b 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -2,30 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#define FML_USED_ON_EMBEDDER - -#include "lib/fxl/build_config.h" - -#if OS_WIN -#define FLUTTER_EXPORT __declspec(dllexport) -#else // OS_WIN #define FLUTTER_EXPORT __attribute__((visibility("default"))) -#endif // OS_WIN #include "flutter/shell/platform/embedder/embedder.h" #include - -#include "flutter/assets/directory_asset_bundle.h" -#include "flutter/common/task_runners.h" -#include "flutter/fml/file.h" +#include "flutter/common/threads.h" #include "flutter/fml/message_loop.h" -#include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/switches.h" -#include "flutter/shell/platform/embedder/embedder.h" -#include "flutter/shell/platform/embedder/embedder_engine.h" #include "flutter/shell/platform/embedder/platform_view_embedder.h" -#include "lib/fxl/command_line.h" #include "lib/fxl/functional/make_copyable.h" #define SAFE_ACCESS(pointer, member, default_value) \ @@ -57,6 +41,21 @@ bool IsRendererValid(const FlutterRendererConfig* config) { return true; } +class PlatformViewHolder { + public: + PlatformViewHolder(std::shared_ptr ptr) + : platform_view_(std::move(ptr)) {} + + std::shared_ptr view() const { + return platform_view_; + } + + private: + std::shared_ptr platform_view_; + + FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewHolder); +}; + struct _FlutterPlatformMessageResponseHandle { fxl::RefPtr message; }; @@ -66,7 +65,6 @@ FlutterResult FlutterEngineRun(size_t version, const FlutterProjectArgs* args, void* user_data, FlutterEngine* engine_out) { - // Step 0: Figure out arguments for shell creation. if (version != FLUTTER_ENGINE_VERSION) { return kInvalidLibraryVersion; } @@ -89,44 +87,51 @@ FlutterResult FlutterEngineRun(size_t version, return kInvalidArguments; } - auto make_current = [ptr = config->open_gl.make_current, - user_data]() -> bool { return ptr(user_data); }; + auto make_current = + [ ptr = config->open_gl.make_current, user_data ]()->bool { + return ptr(user_data); + }; - auto clear_current = [ptr = config->open_gl.clear_current, - user_data]() -> bool { return ptr(user_data); }; + auto clear_current = + [ ptr = config->open_gl.clear_current, user_data ]()->bool { + return ptr(user_data); + }; - auto present = [ptr = config->open_gl.present, user_data]() -> bool { + auto present = [ ptr = config->open_gl.present, user_data ]()->bool { return ptr(user_data); }; - auto fbo_callback = [ptr = config->open_gl.fbo_callback, - user_data]() -> intptr_t { return ptr(user_data); }; + auto fbo_callback = + [ ptr = config->open_gl.fbo_callback, user_data ]()->intptr_t { + return ptr(user_data); + }; shell::PlatformViewEmbedder::PlatformMessageResponseCallback platform_message_response_callback = nullptr; if (SAFE_ACCESS(args, platform_message_callback, nullptr) != nullptr) { platform_message_response_callback = - [ptr = args->platform_message_callback, - user_data](fxl::RefPtr message) { - auto handle = new FlutterPlatformMessageResponseHandle(); - const FlutterPlatformMessage incoming_message = { - .struct_size = sizeof(FlutterPlatformMessage), - .channel = message->channel().c_str(), - .message = message->data().data(), - .message_size = message->data().size(), - .response_handle = handle, - }; - handle->message = std::move(message); - return ptr(&incoming_message, user_data); - }; + [ ptr = args->platform_message_callback, + user_data ](fxl::RefPtr message) { + auto handle = new FlutterPlatformMessageResponseHandle(); + const FlutterPlatformMessage incoming_message = { + .struct_size = sizeof(FlutterPlatformMessage), + .channel = message->channel().c_str(), + .message = message->data().data(), + .message_size = message->data().size(), + .response_handle = handle, + }; + handle->message = std::move(message); + return ptr(&incoming_message, user_data); + }; } const FlutterOpenGLRendererConfig* open_gl_config = &config->open_gl; std::function make_resource_current_callback = nullptr; if (SAFE_ACCESS(open_gl_config, make_resource_current, nullptr) != nullptr) { - make_resource_current_callback = [ptr = - config->open_gl.make_resource_current, - user_data]() { return ptr(user_data); }; + make_resource_current_callback = + [ ptr = config->open_gl.make_resource_current, user_data ]() { + return ptr(user_data); + }; } std::string icu_data_path; @@ -142,33 +147,18 @@ FlutterResult FlutterEngineRun(size_t version, SAFE_ACCESS(args, command_line_argv, nullptr)); } - blink::Settings settings = shell::SettingsFromCommandLine(command_line); - settings.icu_data_path = icu_data_path; - settings.main_dart_file_path = args->main_path; - settings.packages_file_path = args->packages_path; - settings.assets_path = args->assets_path; - settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { - fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); - }; - settings.task_observer_remove = [](intptr_t key) { - fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); - }; - - // Create a thread host with the current thread as the platform thread and all - // other threads managed. - shell::ThreadHost thread_host("io.flutter", shell::ThreadHost::Type::GPU | - shell::ThreadHost::Type::IO | - shell::ThreadHost::Type::UI); - fml::MessageLoop::EnsureInitializedForCurrentThread(); - blink::TaskRunners task_runners( - "io.flutter", - fml::MessageLoop::GetCurrent().GetTaskRunner(), // platform - thread_host.gpu_thread->GetTaskRunner(), // gpu - thread_host.ui_thread->GetTaskRunner(), // ui - thread_host.io_thread->GetTaskRunner() // io - ); - - shell::PlatformViewEmbedder::DispatchTable dispatch_table = { + static std::once_flag once_shell_initialization; + std::call_once(once_shell_initialization, [&]() { + fxl::CommandLine null_command_line; + shell::Shell::InitStandalone( + std::move(command_line), + icu_data_path, // icu data path default lookup. + "", // application library not supported in JIT mode. + args->assets_path + ); + }); + + shell::PlatformViewEmbedder::DispatchTable table = { .gl_make_current_callback = make_current, .gl_clear_current_callback = clear_current, .gl_present_callback = present, @@ -177,55 +167,31 @@ FlutterResult FlutterEngineRun(size_t version, .gl_make_resource_current_callback = make_resource_current_callback, }; - shell::Shell::CreateCallback on_create_platform_view = - [dispatch_table](shell::Shell& shell) { - return std::make_unique( - shell, // delegate - shell.GetTaskRunners(), // task runners - dispatch_table // embedder dispatch table - ); - }; - - shell::Shell::CreateCallback on_create_rasterizer = - [](shell::Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }; - - // Step 1: Create the engine. - auto embedder_engine = - std::make_unique(std::move(thread_host), // - std::move(task_runners), // - settings, // - on_create_platform_view, // - on_create_rasterizer // - ); - - if (!embedder_engine->IsValid()) { - return kInvalidArguments; - } - - // Step 2: Setup the rendering surface. - if (!embedder_engine->NotifyCreated()) { - return kInvalidArguments; - } - - // Step 3: Run the engine. - auto run_configuration = shell::RunConfiguration::InferFromSettings(settings); - - run_configuration.AddAssetResolver( - std::make_unique( - fml::Duplicate(settings.assets_dir))); + auto platform_view = std::make_shared(table); + platform_view->Attach(); + + std::string assets(args->assets_path); + std::string main(args->main_path); + std::string packages(args->packages_path); + + blink::Threads::UI()->PostTask([ + weak_engine = platform_view->engine().GetWeakPtr(), // + assets = std::move(assets), // + main = std::move(main), // + packages = std::move(packages) // + ] { + if (auto engine = weak_engine) { + if (main.empty()) { + engine->RunBundle(assets); + } else { + engine->RunBundleAndSource(assets, main, packages); + } + } + }); + + *engine_out = reinterpret_cast( + new PlatformViewHolder(std::move(platform_view))); - run_configuration.AddAssetResolver( - std::make_unique(fml::OpenFile( - settings.assets_path.c_str(), fml::OpenPermission::kRead, true))); - - if (!embedder_engine->Run(std::move(run_configuration))) { - return kInvalidArguments; - } - - // Finally! Release the ownership of the embedder engine to the caller. - *engine_out = reinterpret_cast(embedder_engine.release()); return kSuccess; } @@ -233,9 +199,7 @@ FlutterResult FlutterEngineShutdown(FlutterEngine engine) { if (engine == nullptr) { return kInvalidArguments; } - auto embedder_engine = reinterpret_cast(engine); - embedder_engine->NotifyDestroyed(); - delete embedder_engine; + delete reinterpret_cast(engine); return kSuccess; } @@ -246,16 +210,21 @@ FlutterResult FlutterEngineSendWindowMetricsEvent( return kInvalidArguments; } + auto holder = reinterpret_cast(engine); + blink::ViewportMetrics metrics; metrics.physical_width = SAFE_ACCESS(flutter_metrics, width, 0.0); metrics.physical_height = SAFE_ACCESS(flutter_metrics, height, 0.0); metrics.device_pixel_ratio = SAFE_ACCESS(flutter_metrics, pixel_ratio, 1.0); - return reinterpret_cast(engine)->SetViewportMetrics( - std::move(metrics)) - ? kSuccess - : kInvalidArguments; + blink::Threads::UI()->PostTask( + [ weak_engine = holder->view()->engine().GetWeakPtr(), metrics ] { + if (auto engine = weak_engine) { + engine->SetViewportMetrics(metrics); + } + }); + return kSuccess; } inline blink::PointerData::Change ToPointerDataChange( @@ -298,10 +267,19 @@ FlutterResult FlutterEngineSendPointerEvent(FlutterEngine engine, reinterpret_cast(current) + current->struct_size); } - return reinterpret_cast(engine) - ->DispatchPointerDataPacket(std::move(packet)) - ? kSuccess - : kInvalidArguments; + blink::Threads::UI()->PostTask(fxl::MakeCopyable([ + weak_engine = reinterpret_cast(engine) + ->view() + ->engine() + .GetWeakPtr(), + packet = std::move(packet) + ] { + if (auto engine = weak_engine) { + engine->DispatchPointerDataPacket(*packet); + } + })); + + return kSuccess; } FlutterResult FlutterEngineSendPlatformMessage( @@ -316,6 +294,8 @@ FlutterResult FlutterEngineSendPlatformMessage( return kInvalidArguments; } + auto holder = reinterpret_cast(engine); + auto message = fxl::MakeRefCounted( flutter_message->channel, std::vector( @@ -323,10 +303,13 @@ FlutterResult FlutterEngineSendPlatformMessage( flutter_message->message + flutter_message->message_size), nullptr); - return reinterpret_cast(engine)->SendPlatformMessage( - std::move(message)) - ? kSuccess - : kInvalidArguments; + blink::Threads::UI()->PostTask( + [ weak_engine = holder->view()->engine().GetWeakPtr(), message ] { + if (auto engine = weak_engine) { + engine->DispatchPlatformMessage(message); + } + }); + return kSuccess; } FlutterResult FlutterEngineSendPlatformMessageResponse( diff --git a/shell/platform/embedder/embedder_engine.cc b/shell/platform/embedder/embedder_engine.cc deleted file mode 100644 index 7416441d7902e..0000000000000 --- a/shell/platform/embedder/embedder_engine.cc +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright 2017 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. - -#include "flutter/shell/platform/embedder/embedder_engine.h" - -#include "lib/fxl/functional/make_copyable.h" - -#ifdef ERROR -#undef ERROR -#endif - -namespace shell { - -EmbedderEngine::EmbedderEngine( - ThreadHost thread_host, - blink::TaskRunners task_runners, - blink::Settings settings, - Shell::CreateCallback on_create_platform_view, - Shell::CreateCallback on_create_rasterizer) - : thread_host_(std::move(thread_host)), - shell_(Shell::Create(std::move(task_runners), - std::move(settings), - on_create_platform_view, - on_create_rasterizer)) { - is_valid_ = shell_ != nullptr; -} - -EmbedderEngine::~EmbedderEngine() = default; - -bool EmbedderEngine::IsValid() const { - return is_valid_; -} - -bool EmbedderEngine::NotifyCreated() { - if (!IsValid()) { - return false; - } - - shell_->GetPlatformView()->NotifyCreated(); - return true; -} - -bool EmbedderEngine::NotifyDestroyed() { - if (!IsValid()) { - return false; - } - - shell_->GetPlatformView()->NotifyDestroyed(); - return true; -} - -bool EmbedderEngine::Run(RunConfiguration run_configuration) { - if (!IsValid()) { - return false; - } - - shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - fxl::MakeCopyable([engine = shell_->GetEngine(), // engine - config = std::move(run_configuration) // config - ]() mutable { - if (engine) { - auto result = engine->Run(std::move(config)); - if (!result) { - FXL_LOG(ERROR) << "Could not launch the engine with configuration."; - } - } - })); - - return true; -} - -bool EmbedderEngine::SetViewportMetrics(blink::ViewportMetrics metrics) { - if (!IsValid()) { - return false; - } - - shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - [engine = shell_->GetEngine(), metrics = std::move(metrics)]() { - if (engine) { - engine->SetViewportMetrics(std::move(metrics)); - } - }); - return true; -} - -bool EmbedderEngine::DispatchPointerDataPacket( - std::unique_ptr packet) { - if (!IsValid() || !packet) { - return false; - } - - shell_->GetTaskRunners().GetUITaskRunner()->PostTask(fxl::MakeCopyable( - [engine = shell_->GetEngine(), packet = std::move(packet)] { - if (engine) { - engine->DispatchPointerDataPacket(*packet); - } - })); - - return true; -} - -bool EmbedderEngine::SendPlatformMessage( - fxl::RefPtr message) { - if (!IsValid() || !message) { - return false; - } - - shell_->GetTaskRunners().GetUITaskRunner()->PostTask( - [engine = shell_->GetEngine(), message] { - if (engine) { - engine->DispatchPlatformMessage(message); - } - }); - - return true; -} - -} // namespace shell diff --git a/shell/platform/embedder/embedder_engine.h b/shell/platform/embedder/embedder_engine.h deleted file mode 100644 index c01b86c2aac47..0000000000000 --- a/shell/platform/embedder/embedder_engine.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2017 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_EMBEDDER_EMBEDDER_ENGINE_H_ -#define FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_ENGINE_H_ - -#include - -#include "flutter/shell/common/shell.h" -#include "flutter/shell/common/thread_host.h" -#include "flutter/shell/platform/embedder/embedder.h" -#include "lib/fxl/macros.h" - -namespace shell { - -// The object that is returned to the embedder as an opaque pointer to the -// instance of the Flutter engine. -class EmbedderEngine { - public: - EmbedderEngine(ThreadHost thread_host, blink::TaskRunners task_runners, - blink::Settings settings, - Shell::CreateCallback on_create_platform_view, - Shell::CreateCallback on_create_rasterizer); - - ~EmbedderEngine(); - - bool NotifyCreated(); - - bool NotifyDestroyed(); - - bool Run(RunConfiguration run_configuration); - - bool IsValid() const; - - bool SetViewportMetrics(blink::ViewportMetrics metrics); - - bool DispatchPointerDataPacket( - std::unique_ptr packet); - - bool SendPlatformMessage(fxl::RefPtr message); - - private: - const ThreadHost thread_host_; - std::unique_ptr shell_; - bool is_valid_ = false; - - FXL_DISALLOW_COPY_AND_ASSIGN(EmbedderEngine); -}; - -} // namespace shell - -#endif // FLUTTER_SHELL_PLATFORM_EMBEDDER_EMBEDDER_ENGINE_H_ diff --git a/shell/platform/embedder/platform_view_embedder.cc b/shell/platform/embedder/platform_view_embedder.cc index db1bea35c691e..46e0390770da4 100644 --- a/shell/platform/embedder/platform_view_embedder.cc +++ b/shell/platform/embedder/platform_view_embedder.cc @@ -3,18 +3,17 @@ // found in the LICENSE file. #include "flutter/shell/platform/embedder/platform_view_embedder.h" - -#include "flutter/shell/common/io_manager.h" +#include "flutter/shell/gpu/gpu_rasterizer.h" namespace shell { -PlatformViewEmbedder::PlatformViewEmbedder(PlatformView::Delegate& delegate, - blink::TaskRunners task_runners, - DispatchTable dispatch_table) - : PlatformView(delegate, std::move(task_runners)), +PlatformViewEmbedder::PlatformViewEmbedder(DispatchTable dispatch_table) + : PlatformView(std::make_unique(nullptr)), dispatch_table_(dispatch_table) {} -PlatformViewEmbedder::~PlatformViewEmbedder() = default; +PlatformViewEmbedder::~PlatformViewEmbedder() { + NotifyDestroyed(); +} bool PlatformViewEmbedder::GLContextMakeCurrent() { return dispatch_table_.gl_make_current_callback(); @@ -32,6 +31,33 @@ intptr_t PlatformViewEmbedder::GLContextFBO() const { return dispatch_table_.gl_fbo_callback(); } +void PlatformViewEmbedder::Attach() { + CreateEngine(); + NotifyCreated(std::make_unique(this)); + + if (dispatch_table_.gl_make_resource_current_callback != nullptr) { + SetupResourceContextOnIOThread(); + } +} + +bool PlatformViewEmbedder::ResourceContextMakeCurrent() { + if (dispatch_table_.gl_make_resource_current_callback == nullptr) { + return false; + } + return dispatch_table_.gl_make_resource_current_callback(); +} + +void PlatformViewEmbedder::RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) { + FXL_LOG(INFO) << "Hot reloading is unsupported on this platform."; +} + +void PlatformViewEmbedder::SetAssetBundlePath( + const std::string& assets_directory) { + FXL_LOG(INFO) << "Set asset bundle path is unsupported on this platform."; +} + void PlatformViewEmbedder::HandlePlatformMessage( fxl::RefPtr message) { if (!message) { @@ -50,17 +76,4 @@ void PlatformViewEmbedder::HandlePlatformMessage( dispatch_table_.platform_message_response_callback(std::move(message)); } -std::unique_ptr PlatformViewEmbedder::CreateRenderingSurface() { - return std::make_unique(this); -} - -sk_sp PlatformViewEmbedder::CreateResourceContext() const { - auto callback = dispatch_table_.gl_make_resource_current_callback; - if (callback && callback()) { - return IOManager::CreateCompatibleResourceLoadingContext( - GrBackend::kOpenGL_GrBackend); - } - return nullptr; -} - } // namespace shell diff --git a/shell/platform/embedder/platform_view_embedder.h b/shell/platform/embedder/platform_view_embedder.h index a5b76dfaa07ba..c287fc5ac86f1 100644 --- a/shell/platform/embedder/platform_view_embedder.h +++ b/shell/platform/embedder/platform_view_embedder.h @@ -12,8 +12,7 @@ namespace shell { -class PlatformViewEmbedder final : public PlatformView, - public GPUSurfaceGLDelegate { +class PlatformViewEmbedder : public PlatformView, public GPUSurfaceGLDelegate { public: using PlatformMessageResponseCallback = std::function)>; @@ -27,11 +26,9 @@ class PlatformViewEmbedder final : public PlatformView, std::function gl_make_resource_current_callback; // optional }; - PlatformViewEmbedder(PlatformView::Delegate& delegate, - blink::TaskRunners task_runners, - DispatchTable dispatch_table); + PlatformViewEmbedder(DispatchTable dispatch_table); - ~PlatformViewEmbedder() override; + ~PlatformViewEmbedder(); // |shell::GPUSurfaceGLDelegate| bool GLContextMakeCurrent() override; @@ -46,17 +43,25 @@ class PlatformViewEmbedder final : public PlatformView, intptr_t GLContextFBO() const override; // |shell::PlatformView| - void HandlePlatformMessage( - fxl::RefPtr message) override; + void Attach() override; - private: - DispatchTable dispatch_table_; + // |shell::PlatformView| + bool ResourceContextMakeCurrent() override; + + // |shell::PlatformView| + void RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) override; // |shell::PlatformView| - std::unique_ptr CreateRenderingSurface() override; + void SetAssetBundlePath(const std::string& assets_directory) override; // |shell::PlatformView| - sk_sp CreateResourceContext() const override; + void HandlePlatformMessage( + fxl::RefPtr message) override; + + private: + DispatchTable dispatch_table_; FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewEmbedder); }; diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn new file mode 100644 index 0000000000000..6e9f1f596b09d --- /dev/null +++ b/shell/platform/linux/BUILD.gn @@ -0,0 +1,23 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +executable("linux") { + output_name = "flutter_tester" + + sources = [ + "main_linux.cc", + ] + + deps = [ + "//third_party/dart/runtime:libdart_jit", + "//third_party/dart/runtime/bin:embedded_dart_io", + "$flutter_root/common", + "$flutter_root/fml", + "$flutter_root/shell/common", + "$flutter_root/shell/testing", + "//garnet/public/lib/fxl", + "//third_party/skia", + "//topaz/lib/tonic", + ] +} diff --git a/shell/platform/linux/main_linux.cc b/shell/platform/linux/main_linux.cc new file mode 100644 index 0000000000000..a20d425ed1eed --- /dev/null +++ b/shell/platform/linux/main_linux.cc @@ -0,0 +1,142 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/common/threads.h" +#include "flutter/fml/message_loop.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/switches.h" +#include "flutter/shell/testing/test_runner.h" +#include "flutter/shell/testing/testing.h" +#include "flutter/sky/engine/public/web/Sky.h" +#include "lib/fxl/command_line.h" +#include "lib/tonic/dart_microtask_queue.h" +#include "third_party/dart/runtime/bin/embedded_dart_io.h" + +namespace { + +// Exit codes used by the Dart command line tool. +const int kApiErrorExitCode = 253; +const int kCompilationErrorExitCode = 254; +const int kErrorExitCode = 255; + +// Checks whether the engine's main Dart isolate has no pending work. If so, +// then exit the given message loop. +class ScriptCompletionTaskObserver : public fml::TaskObserver { + public: + ScriptCompletionTaskObserver(fxl::RefPtr task_runner) + : main_task_runner_(std::move(task_runner)), + prev_live_(false), + last_error_(tonic::kNoError) {} + + void DidProcessTask() override { + shell::TestRunner& test_runner = shell::TestRunner::Shared(); + shell::Engine& engine = test_runner.platform_view().engine(); + + if (engine.GetLoadScriptError() != tonic::kNoError) { + last_error_ = engine.GetLoadScriptError(); + main_task_runner_->PostTask( + []() { fml::MessageLoop::GetCurrent().Terminate(); }); + return; + } + + bool live = engine.UIIsolateHasLivePorts(); + if (prev_live_ && !live) { + last_error_ = engine.GetUIIsolateLastError(); + main_task_runner_->PostTask( + []() { fml::MessageLoop::GetCurrent().Terminate(); }); + } + prev_live_ = live; + } + + tonic::DartErrorHandleType last_error() { return last_error_; } + + private: + fxl::RefPtr main_task_runner_; + bool prev_live_; + tonic::DartErrorHandleType last_error_; +}; + +int ConvertErrorTypeToExitCode(tonic::DartErrorHandleType error) { + switch (error) { + case tonic::kCompilationErrorType: + return kCompilationErrorExitCode; + case tonic::kApiErrorType: + return kApiErrorExitCode; + case tonic::kUnknownErrorType: + return kErrorExitCode; + default: + return 0; + } +} + +void RunNonInteractive(fxl::CommandLine initial_command_line, + bool run_forever) { + // This is a platform thread (i.e not one created by fml::Thread), so perform + // one time initialization. + fml::MessageLoop::EnsureInitializedForCurrentThread(); + + std::string bundle_path = ""; + initial_command_line.GetOptionValue( + FlagForSwitch(shell::Switch::FlutterAssetsDir), &bundle_path); + + shell::Shell::InitStandalone(initial_command_line, + /* icu_data_path= */ "", + /* application_library_path= */ "", bundle_path); + + // Note that this task observer must be added after the observer that drains + // the microtask queue. + ScriptCompletionTaskObserver task_observer( + fml::MessageLoop::GetCurrent().GetTaskRunner()); + if (!run_forever) { + blink::Threads::UI()->PostTask([&task_observer] { + fml::MessageLoop::GetCurrent().AddTaskObserver(&task_observer); + }); + } + + if (!shell::InitForTesting(initial_command_line)) { + shell::PrintUsage("flutter_tester"); + exit(EXIT_FAILURE); + return; + } + + fml::MessageLoop::GetCurrent().Run(); + + shell::TestRunner& test_runner = shell::TestRunner::Shared(); + tonic::DartErrorHandleType error = + test_runner.platform_view().engine().GetLoadScriptError(); + if (error == tonic::kNoError) + error = task_observer.last_error(); + if (error == tonic::kNoError) { + fxl::AutoResetWaitableEvent latch; + blink::Threads::UI()->PostTask([&error, &latch] { + error = tonic::DartMicrotaskQueue::GetForCurrentThread()->GetLastError(); + latch.Signal(); + }); + latch.Wait(); + } + + // The script has completed and the engine may not be in a clean state, + // so just stop the process. + exit(ConvertErrorTypeToExitCode(error)); +} + +} // namespace + +int main(int argc, char* argv[]) { + dart::bin::SetExecutableName(argv[0]); + dart::bin::SetExecutableArguments(argc - 1, argv); + + auto command_line = fxl::CommandLineFromArgcArgv(argc, argv); + + if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { + shell::PrintUsage("flutter_tester"); + return EXIT_SUCCESS; + } + + bool run_forever = + command_line.HasOption(shell::FlagForSwitch(shell::Switch::RunForever)); + RunNonInteractive(std::move(command_line), run_forever); + return EXIT_SUCCESS; +} diff --git a/shell/platform/win/BUILD.gn b/shell/platform/win/BUILD.gn new file mode 100644 index 0000000000000..b4a2fe5033c18 --- /dev/null +++ b/shell/platform/win/BUILD.gn @@ -0,0 +1,30 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +executable("win") { + output_name = "flutter_tester" + + sources = [ + "main_win.cc", + ] + + deps = [ + "//flutter/common", + "//flutter/flow", + "//flutter/fml", + "//flutter/shell/common", + "//flutter/shell/testing", + "//flutter/sky/engine/wtf", + "//garnet/public/lib/fxl", + "//third_party/dart/runtime/bin:embedded_dart_io", + "//third_party/dart/runtime:libdart_jit", + "//third_party/skia", + "//topaz/lib/tonic", + ] + + libs = [ + "iphlpapi.lib", + "Rpcrt4.lib" + ] +} diff --git a/shell/platform/win/main_win.cc b/shell/platform/win/main_win.cc new file mode 100644 index 0000000000000..c31c88ca915cb --- /dev/null +++ b/shell/platform/win/main_win.cc @@ -0,0 +1,142 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include + +#include "flutter/common/threads.h" +#include "flutter/fml/message_loop.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/common/switches.h" +#include "flutter/shell/testing/test_runner.h" +#include "flutter/shell/testing/testing.h" +#include "lib/fxl/command_line.h" +#include "lib/tonic/dart_microtask_queue.h" +#include "third_party/dart/runtime/bin/embedded_dart_io.h" + +namespace { + +// Exit codes used by the Dart command line tool. +const int kApiErrorExitCode = 253; +const int kCompilationErrorExitCode = 254; +const int kErrorExitCode = 255; + +// Checks whether the engine's main Dart isolate has no pending work. If so, +// then exit the given message loop. +class ScriptCompletionTaskObserver : public fml::TaskObserver { + public: + ScriptCompletionTaskObserver(fxl::RefPtr task_runner) + : main_task_runner_(std::move(task_runner)), + prev_live_(false), + last_error_(tonic::kNoError) {} + + void DidProcessTask() override { + shell::TestRunner& test_runner = shell::TestRunner::Shared(); + shell::Engine& engine = test_runner.platform_view().engine(); + + if (engine.GetLoadScriptError() != tonic::kNoError) { + last_error_ = engine.GetLoadScriptError(); + main_task_runner_->PostTask( + []() { fml::MessageLoop::GetCurrent().Terminate(); }); + return; + } + + bool live = engine.UIIsolateHasLivePorts(); + if (prev_live_ && !live) { + last_error_ = engine.GetUIIsolateLastError(); + main_task_runner_->PostTask( + []() { fml::MessageLoop::GetCurrent().Terminate(); }); + } + prev_live_ = live; + } + + tonic::DartErrorHandleType last_error() { return last_error_; } + + private: + fxl::RefPtr main_task_runner_; + bool prev_live_; + tonic::DartErrorHandleType last_error_; +}; + +int ConvertErrorTypeToExitCode(tonic::DartErrorHandleType error) { + switch (error) { + case tonic::kCompilationErrorType: + return kCompilationErrorExitCode; + case tonic::kApiErrorType: + return kApiErrorExitCode; + case tonic::kUnknownErrorType: + return kErrorExitCode; + default: + return 0; + } +} + +void RunNonInteractive(fxl::CommandLine initial_command_line, + bool run_forever) { + // This is a platform thread (i.e not one created by fml::Thread), so perform + // one time initialization. + fml::MessageLoop::EnsureInitializedForCurrentThread(); + + std::string bundle_path = ""; + initial_command_line.GetOptionValue( + FlagForSwitch(shell::Switch::FlutterAssetsDir), &bundle_path); + + shell::Shell::InitStandalone(initial_command_line, + /* icu_data_path= */ "", + /* application_library_path= */ "", bundle_path); + + // Note that this task observer must be added after the observer that drains + // the microtask queue. + ScriptCompletionTaskObserver task_observer( + fml::MessageLoop::GetCurrent().GetTaskRunner()); + if (!run_forever) { + blink::Threads::UI()->PostTask([&task_observer] { + fml::MessageLoop::GetCurrent().AddTaskObserver(&task_observer); + }); + } + + if (!shell::InitForTesting(initial_command_line)) { + shell::PrintUsage("flutter_tester"); + ::ExitProcess(EXIT_FAILURE); + return; + } + + fml::MessageLoop::GetCurrent().Run(); + shell::TestRunner& test_runner = shell::TestRunner::Shared(); + tonic::DartErrorHandleType error = + test_runner.platform_view().engine().GetLoadScriptError(); + if (error == tonic::kNoError) + error = task_observer.last_error(); + if (error == tonic::kNoError) { + fxl::AutoResetWaitableEvent latch; + blink::Threads::UI()->PostTask([&error, &latch] { + error = tonic::DartMicrotaskQueue::GetForCurrentThread()->GetLastError(); + latch.Signal(); + }); + latch.Wait(); + } + + // The script has completed and the engine may not be in a clean state, + // so just stop the process. + ::ExitProcess(ConvertErrorTypeToExitCode(error)); +} + +} // namespace + +int main(int argc, char* argv[]) { + dart::bin::SetExecutableName(argv[0]); + dart::bin::SetExecutableArguments(argc - 1, argv); + + auto command_line = fxl::CommandLineFromArgcArgv(argc, argv); + + if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { + shell::PrintUsage("flutter_tester"); + return EXIT_SUCCESS; + } + + bool run_forever = + command_line.HasOption(shell::FlagForSwitch(shell::Switch::RunForever)); + RunNonInteractive(std::move(command_line), run_forever); + return EXIT_SUCCESS; +} diff --git a/shell/testing/BUILD.gn b/shell/testing/BUILD.gn index f11a3a2d07501..659c241cc49b8 100644 --- a/shell/testing/BUILD.gn +++ b/shell/testing/BUILD.gn @@ -2,30 +2,24 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -executable("testing") { - testonly = true - - output_name = "flutter_tester" - - public_configs = [ "$flutter_root:config" ] - +source_set("testing") { sources = [ - "tester_main.cc", + "platform_view_test.cc", + "platform_view_test.h", + "test_runner.cc", + "test_runner.h", + "testing.cc", + "testing.h", ] deps = [ - "$flutter_root/assets", "$flutter_root/common", - "$flutter_root/fml", "$flutter_root/shell/common", "//garnet/public/lib/fxl", - "//third_party/dart/runtime:libdart_jit", - "//third_party/dart/runtime/bin:embedded_dart_io", "//third_party/skia", - "//topaz/lib/tonic", ] - if (is_linux) { - ldflags = [ "-rdynamic" ] - } + public_configs = [ + "$flutter_root:config", + ] } diff --git a/shell/testing/platform_view_test.cc b/shell/testing/platform_view_test.cc new file mode 100644 index 0000000000000..a59684d31bc94 --- /dev/null +++ b/shell/testing/platform_view_test.cc @@ -0,0 +1,32 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/testing/platform_view_test.h" + +#include "flutter/shell/common/null_rasterizer.h" +#include "flutter/shell/common/shell.h" + +namespace shell { + +PlatformViewTest::PlatformViewTest() + : PlatformView(std::unique_ptr(new NullRasterizer())) {} + +void PlatformViewTest::Attach() { + CreateEngine(); +} + +PlatformViewTest::~PlatformViewTest() = default; + +bool PlatformViewTest::ResourceContextMakeCurrent() { + return false; +} + +void PlatformViewTest::RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) {} + +void PlatformViewTest::SetAssetBundlePath(const std::string& assets_directory) { +} + +} // namespace shell diff --git a/shell/testing/platform_view_test.h b/shell/testing/platform_view_test.h new file mode 100644 index 0000000000000..3612d0363ab58 --- /dev/null +++ b/shell/testing/platform_view_test.h @@ -0,0 +1,38 @@ +// Copyright 2016 The Chromium 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 SHELL_TESTING_PLATFORM_VIEW_TEST_H_ +#define SHELL_TESTING_PLATFORM_VIEW_TEST_H_ + +#include "flutter/shell/common/platform_view.h" +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" + +namespace shell { + +class Shell; + +class PlatformViewTest : public PlatformView { + public: + PlatformViewTest(); + + ~PlatformViewTest(); + + virtual void Attach() override; + + bool ResourceContextMakeCurrent() override; + + void RunFromSource(const std::string& assets_directory, + const std::string& main, + const std::string& packages) override; + + void SetAssetBundlePath(const std::string& assets_directory) override; + + private: + FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewTest); +}; + +} // namespace shell + +#endif // SHELL_TESTING_PLATFORM_VIEW_TEST_H_ diff --git a/shell/testing/test_runner.cc b/shell/testing/test_runner.cc new file mode 100644 index 0000000000000..838b04120c773 --- /dev/null +++ b/shell/testing/test_runner.cc @@ -0,0 +1,48 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/testing/test_runner.h" + +#include + +#include "flutter/common/threads.h" +#include "flutter/shell/common/platform_view.h" +#include "flutter/shell/common/shell.h" +#include "flutter/shell/testing/platform_view_test.h" + +namespace shell { + +TestRunner::TestRunner() + : platform_view_(std::make_shared()) { + platform_view_->Attach(); + blink::ViewportMetrics metrics; + metrics.device_pixel_ratio = 3.0; + metrics.physical_width = 2400; // 800 at 3x resolution + metrics.physical_height = 1800; // 600 at 3x resolution + + blink::Threads::UI()->PostTask( + [ engine = platform_view_->engine().GetWeakPtr(), metrics ] { + if (engine) + engine->SetViewportMetrics(metrics); + }); +} + +TestRunner::~TestRunner() = default; + +TestRunner& TestRunner::Shared() { + static TestRunner* g_test_runner = nullptr; + if (!g_test_runner) + g_test_runner = new TestRunner(); + return *g_test_runner; +} + +void TestRunner::Run(const TestDescriptor& test) { + blink::Threads::UI()->PostTask( + [ engine = platform_view_->engine().GetWeakPtr(), test ] { + if (engine) + engine->RunBundleAndSource(std::string(), test.path, test.packages); + }); +} + +} // namespace shell diff --git a/shell/testing/test_runner.h b/shell/testing/test_runner.h new file mode 100644 index 0000000000000..8f303d7eb7683 --- /dev/null +++ b/shell/testing/test_runner.h @@ -0,0 +1,42 @@ +// Copyright 2015 The Chromium 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 SHELL_TESTING_TEST_RUNNER_H_ +#define SHELL_TESTING_TEST_RUNNER_H_ + +#include +#include + +#include "lib/fxl/macros.h" +#include "lib/fxl/memory/weak_ptr.h" + +namespace shell { + +class PlatformView; + +class TestRunner { + public: + static TestRunner& Shared(); + + struct TestDescriptor { + std::string path; + std::string packages; + }; + + void Run(const TestDescriptor& test); + + PlatformView& platform_view() { return *platform_view_; } + + private: + TestRunner(); + ~TestRunner(); + + std::shared_ptr platform_view_; + + FXL_DISALLOW_COPY_AND_ASSIGN(TestRunner); +}; + +} // namespace shell + +#endif // SHELL_TESTING_TEST_RUNNER_H_ diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc deleted file mode 100644 index a9e7bafc74d93..0000000000000 --- a/shell/testing/tester_main.cc +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2018 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. - -#define FML_USED_ON_EMBEDDER - -#include - -#include "flutter/assets/asset_manager.h" -#include "flutter/assets/directory_asset_bundle.h" -#include "flutter/fml/file.h" -#include "flutter/fml/message_loop.h" -#include "flutter/fml/paths.h" -#include "flutter/shell/common/platform_view.h" -#include "flutter/shell/common/rasterizer.h" -#include "flutter/shell/common/shell.h" -#include "flutter/shell/common/switches.h" -#include "flutter/shell/common/thread_host.h" -#include "lib/fxl/functional/make_copyable.h" -#include "lib/fxl/synchronization/waitable_event.h" -#include "third_party/dart/runtime/bin/embedded_dart_io.h" - -#ifdef ERROR -#undef ERROR -#endif - -namespace shell { - -// Checks whether the engine's main Dart isolate has no pending work. If so, -// then exit the given message loop. -class ScriptCompletionTaskObserver { - public: - ScriptCompletionTaskObserver(Shell& shell, - fxl::RefPtr main_task_runner, - bool run_forever) - : engine_(shell.GetEngine()), - main_task_runner_(std::move(main_task_runner)), - run_forever_(run_forever) {} - - int GetExitCodeForLastError() const { - // Exit codes used by the Dart command line tool. - const int kApiErrorExitCode = 253; - const int kCompilationErrorExitCode = 254; - const int kErrorExitCode = 255; - switch (last_error_) { - case tonic::kCompilationErrorType: - return kCompilationErrorExitCode; - case tonic::kApiErrorType: - return kApiErrorExitCode; - case tonic::kUnknownErrorType: - return kErrorExitCode; - default: - return 0; - } - } - - void DidProcessTask() { - if (engine_) { - last_error_ = engine_->GetUIIsolateLastError(); - if (engine_->UIIsolateHasLivePorts()) { - // The UI isolate still has live ports and is running. Nothing to do - // just yet. - return; - } - } - - if (run_forever_) { - // We need this script to run forever. We have already recorded the last - // error. Keep going. - return; - } - - if (!has_terminated) { - // Only try to terminate the loop once. - has_terminated = true; - main_task_runner_->PostTask( - []() { fml::MessageLoop::GetCurrent().Terminate(); }); - } - } - - private: - fml::WeakPtr engine_; - fxl::RefPtr main_task_runner_; - bool run_forever_ = false; - tonic::DartErrorHandleType last_error_ = tonic::kUnknownErrorType; - bool has_terminated = false; - - FXL_DISALLOW_COPY_AND_ASSIGN(ScriptCompletionTaskObserver); -}; - -int RunTester(const blink::Settings& settings, bool run_forever) { - const auto thread_label = "io.flutter.test"; - - fml::MessageLoop::EnsureInitializedForCurrentThread(); - - auto current_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner(); - - // Setup a single threaded test runner configuration. - const blink::TaskRunners task_runners(thread_label, // dart thread label - current_task_runner, // platform - current_task_runner, // gpu - current_task_runner, // ui - current_task_runner // io - ); - - Shell::CreateCallback on_create_platform_view = - [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); - }; - - Shell::CreateCallback on_create_rasterizer = [](Shell& shell) { - return std::make_unique(shell.GetTaskRunners()); - }; - - auto shell = Shell::Create(task_runners, // - settings, // - on_create_platform_view, // - on_create_rasterizer // - ); - - if (!shell || !shell->IsSetup()) { - FXL_LOG(ERROR) << "Could not setup the shell."; - return EXIT_FAILURE; - } - - auto isolate_configuration = IsolateConfiguration::CreateForSource( - settings.main_dart_file_path, settings.packages_file_path); - - if (!isolate_configuration) { - FXL_LOG(ERROR) << "Could create isolate configuration."; - return EXIT_FAILURE; - } - - auto asset_manager = fxl::MakeRefCounted(); - asset_manager->PushBack(std::make_unique( - fml::Duplicate(settings.assets_dir))); - asset_manager->PushBack( - std::make_unique(fml::OpenFile( - settings.assets_path.c_str(), fml::OpenPermission::kRead, true))); - - RunConfiguration run_configuration(std::move(isolate_configuration), - std::move(asset_manager)); - - // The script completion task observer that will be installed on the UI thread - // that watched if the engine has any live ports. - ScriptCompletionTaskObserver completion_observer( - *shell, // a valid shell - fml::MessageLoop::GetCurrent() - .GetTaskRunner(), // the message loop to terminate - run_forever // should the exit be ignored - ); - - bool engine_did_run = false; - - shell->GetTaskRunners().GetUITaskRunner()->PostTask(fxl::MakeCopyable( - [&completion_observer, engine = shell->GetEngine(), - config = std::move(run_configuration), &engine_did_run]() mutable { - fml::MessageLoop::GetCurrent().AddTaskObserver( - reinterpret_cast(&completion_observer), - [&completion_observer]() { completion_observer.DidProcessTask(); }); - if (engine->Run(std::move(config))) { - engine_did_run = true; - - blink::ViewportMetrics metrics; - metrics.device_pixel_ratio = 3.0; - metrics.physical_width = 2400; // 800 at 3x resolution - metrics.physical_height = 1800; // 600 at 3x resolution - engine->SetViewportMetrics(metrics); - - } else { - FXL_DLOG(ERROR) << "Could not launch the engine with configuration."; - } - })); - - // Run the message loop and wait for the script to do its thing. - fml::MessageLoop::GetCurrent().Run(); - - // Cleanup the completion observer synchronously as it is living on the - // stack. - fxl::AutoResetWaitableEvent latch; - fml::TaskRunner::RunNowOrPostTask( - shell->GetTaskRunners().GetUITaskRunner(), - [&latch, &completion_observer] { - fml::MessageLoop::GetCurrent().RemoveTaskObserver( - reinterpret_cast(&completion_observer)); - latch.Signal(); - }); - latch.Wait(); - - if (!engine_did_run) { - // If the engine itself didn't have a chance to run, there is no point in - // asking it if there was an error. Signal a failure unconditionally. - return EXIT_FAILURE; - } - - return completion_observer.GetExitCodeForLastError(); -} - -} // namespace shell - -int main(int argc, char* argv[]) { - dart::bin::SetExecutableName(argv[0]); - dart::bin::SetExecutableArguments(argc - 1, argv); - - auto command_line = fxl::CommandLineFromArgcArgv(argc, argv); - - if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { - shell::PrintUsage("flutter_tester"); - return EXIT_SUCCESS; - } - - auto settings = shell::SettingsFromCommandLine(command_line); - if (command_line.positional_args().size() > 0) { - // The tester may not use the switch for the main dart file path. Specifying - // it as a positional argument instead. - settings.main_dart_file_path = command_line.positional_args()[0]; - } - - if (settings.main_dart_file_path.size() == 0) { - FXL_LOG(ERROR) << "Main dart file path not specified."; - return EXIT_FAILURE; - } - - settings.icu_data_path = "icudtl.dat"; - - settings.kernel_snapshot_path = - fml::paths::JoinPaths({settings.assets_path, "platform.dill"}); - - // The tools that read logs get confused if there is a log tag specified. - settings.log_tag = ""; - - settings.task_observer_add = [](intptr_t key, fxl::Closure callback) { - fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback)); - }; - - settings.task_observer_remove = [](intptr_t key) { - fml::MessageLoop::GetCurrent().RemoveTaskObserver(key); - }; - - return shell::RunTester( - settings, - command_line.HasOption(shell::FlagForSwitch(shell::Switch::RunForever))); -} diff --git a/shell/testing/testing.cc b/shell/testing/testing.cc new file mode 100644 index 0000000000000..13a3ab5be3d93 --- /dev/null +++ b/shell/testing/testing.cc @@ -0,0 +1,24 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "flutter/shell/testing/testing.h" + +#include "flutter/shell/common/switches.h" +#include "flutter/shell/testing/test_runner.h" + +namespace shell { + +bool InitForTesting(const fxl::CommandLine& command_line) { + TestRunner::TestDescriptor test; + test.packages = command_line.GetOptionValueWithDefault( + FlagForSwitch(Switch::Packages), ""); + auto args = command_line.positional_args(); + if (args.empty()) + return false; + test.path = args[0]; + TestRunner::Shared().Run(test); + return true; +} + +} // namespace shell diff --git a/shell/testing/testing.h b/shell/testing/testing.h new file mode 100644 index 0000000000000..99f8b4fe983de --- /dev/null +++ b/shell/testing/testing.h @@ -0,0 +1,16 @@ +// Copyright 2015 The Chromium 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 SHELL_TESTING_TESTING_H_ +#define SHELL_TESTING_TESTING_H_ + +#include "lib/fxl/command_line.h" + +namespace shell { + +bool InitForTesting(const fxl::CommandLine& command_line); + +} // namespace shell + +#endif // SHELL_TESTING_TESTING_H_ diff --git a/sky/engine/platform/SharedBuffer.cpp b/sky/engine/platform/SharedBuffer.cpp index bc94f22e97ce6..8577ab16f2938 100644 --- a/sky/engine/platform/SharedBuffer.cpp +++ b/sky/engine/platform/SharedBuffer.cpp @@ -26,6 +26,7 @@ #include "flutter/sky/engine/platform/SharedBuffer.h" +#include "flutter/common/threads.h" #include "flutter/sky/engine/public/platform/Platform.h" #include "flutter/sky/engine/wtf/unicode/UTF8.h" #include "flutter/sky/engine/wtf/unicode/Unicode.h" diff --git a/sky/engine/platform/fonts/FontFallbackList.cpp b/sky/engine/platform/fonts/FontFallbackList.cpp index 4786d65e0d7ad..177f161adaa7e 100644 --- a/sky/engine/platform/fonts/FontFallbackList.cpp +++ b/sky/engine/platform/fonts/FontFallbackList.cpp @@ -37,11 +37,6 @@ namespace blink { -bool gUseTestFonts = false; -void FontFallbackList::SetUseTestFonts(bool useTestFonts) { - gUseTestFonts = useTestFonts; -} - FontFallbackList::FontFallbackList() : m_pageZero(0), m_cachedPrimarySimpleFontData(0), @@ -50,8 +45,7 @@ FontFallbackList::FontFallbackList() m_familyIndex(0), m_generation(FontCache::fontCache()->generation()), m_pitch(UnknownPitch), - m_hasLoadingFallback(false), - m_useTestFonts(gUseTestFonts) {} + m_hasLoadingFallback(false) {} void FontFallbackList::invalidate(PassRefPtr fontSelector) { releaseFontData(); @@ -199,7 +193,7 @@ PassRefPtr FontFallbackList::getFontData( const FontFamily* currFamily = startFamily; while (currFamily && !result) { familyIndex++; - if (currFamily->family().length() || m_useTestFonts) { + if (currFamily->family().length() || Settings::Get().use_test_fonts) { if (m_fontSelector) result = m_fontSelector->getFontData(fontDescription, currFamily->family()); diff --git a/sky/engine/platform/fonts/FontFallbackList.h b/sky/engine/platform/fonts/FontFallbackList.h index 3331387968edc..fdac27e5013bd 100644 --- a/sky/engine/platform/fonts/FontFallbackList.h +++ b/sky/engine/platform/fonts/FontFallbackList.h @@ -103,8 +103,6 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted { m_pageZero = node; } - static void SetUseTestFonts(bool useTestFonts); - private: FontFallbackList(); @@ -127,7 +125,6 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted { unsigned short m_generation; mutable unsigned m_pitch : 3; // Pitch mutable bool m_hasLoadingFallback : 1; - bool m_useTestFonts = false; }; } // namespace blink diff --git a/sky/engine/web/Sky.cpp b/sky/engine/web/Sky.cpp index 52c6243743d7b..e90539e96cf87 100644 --- a/sky/engine/web/Sky.cpp +++ b/sky/engine/web/Sky.cpp @@ -53,6 +53,56 @@ namespace blink { +namespace { + +void didProcessTask() { + tonic::DartMicrotaskQueue::GetForCurrentThread()->RunMicrotasks(); + // FIXME: Report memory usage to dart? +} + +#if defined(OS_FUCHSIA) + +void addMessageLoopObservers() { + fsl::MessageLoop::GetCurrent()->SetAfterTaskCallback(didProcessTask); +} + +void removeMessageLoopObservers() { + fsl::MessageLoop::GetCurrent()->ClearAfterTaskCallback(); +} + +#else // defined(OS_FUCHSIA) + +class RunMicrotasksTaskObserver : public fml::TaskObserver { + public: + RunMicrotasksTaskObserver() = default; + + ~RunMicrotasksTaskObserver() override = default; + + void DidProcessTask() override { didProcessTask(); } +}; + +// FIXME(chinmaygarde): The awkward use of the global here is be cause we cannot +// introduce the fml::TaskObserver subclass in common code because Fuchsia does +// not support the same. Unify the API and remove hack. +static RunMicrotasksTaskObserver* g_run_microtasks_task_observer = nullptr; + +void addMessageLoopObservers() { + g_run_microtasks_task_observer = new RunMicrotasksTaskObserver(); + fml::MessageLoop::GetCurrent().AddTaskObserver( + g_run_microtasks_task_observer); +} + +void removeMessageLoopObservers() { + fml::MessageLoop::GetCurrent().RemoveTaskObserver( + g_run_microtasks_task_observer); + delete g_run_microtasks_task_observer; + g_run_microtasks_task_observer = nullptr; +} + +#endif // defined(OS_FUCHSIA) + +} // namespace + // Make sure we are not re-initialized in the same address space. // Doing so may cause hard to reproduce crashes. static bool s_webKitInitialized = false; @@ -80,9 +130,15 @@ void InitEngine(Platform* platform) { // the initialization thread-safe, but given that so many code paths use // this, initializing this lazily probably doesn't buy us much. WTF::UTF8Encoding(); + + tonic::DartMicrotaskQueue::StartForCurrentThread(); + addMessageLoopObservers(); } void ShutdownEngine() { + removeMessageLoopObservers(); + tonic::DartMicrotaskQueue::GetForCurrentThread()->Destroy(); + // FIXME: Shutdown dart? CoreInitializer::shutdown(); diff --git a/synchronization/BUILD.gn b/synchronization/BUILD.gn index 9ee7680cc1160..977a571c8da30 100644 --- a/synchronization/BUILD.gn +++ b/synchronization/BUILD.gn @@ -4,13 +4,16 @@ source_set("synchronization") { sources = [ + "debug_thread_checker.h", "pipeline.cc", "pipeline.h", "semaphore.cc", "semaphore.h", ] - public_configs = [ "$flutter_root:config" ] + public_configs = [ + "$flutter_root:config", + ] public_deps = [ "$flutter_root/glue", diff --git a/synchronization/debug_thread_checker.h b/synchronization/debug_thread_checker.h new file mode 100644 index 0000000000000..69614eb89d217 --- /dev/null +++ b/synchronization/debug_thread_checker.h @@ -0,0 +1,25 @@ +// Copyright 2016 The Chromium 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_SYNCHRONIZATION_DEBUG_THREAD_CHECKER_H_ +#define FLUTTER_SYNCHRONIZATION_DEBUG_THREAD_CHECKER_H_ + +#ifndef NDEBUG + +#include +#include "lib/fxl/synchronization/thread_checker.h" + +#define FLUTTER_THREAD_CHECKER_DECLARE(x) ::fxl::ThreadChecker x; + +#define FLUTTER_THREAD_CHECKER_CHECK(x) FXL_CHECK(x.IsCreationThreadCurrent()); + +#else // NDEBUG + +#define FLUTTER_THREAD_CHECKER_DECLARE(x) + +#define FLUTTER_THREAD_CHECKER_CHECK(x) + +#endif // NDEBUG + +#endif // FLUTTER_SYNCHRONIZATION_DEBUG_THREAD_CHECKER_H_ diff --git a/synchronization/semaphore.cc b/synchronization/semaphore.cc index 4dc5f6220e350..c6e0bdf9e2d53 100644 --- a/synchronization/semaphore.cc +++ b/synchronization/semaphore.cc @@ -15,12 +15,9 @@ namespace flutter { class PlatformSemaphore { public: explicit PlatformSemaphore(uint32_t count) - : _sem(dispatch_semaphore_create(count)), _initial(count) {} + : _sem(dispatch_semaphore_create(count)) {} ~PlatformSemaphore() { - for (uint32_t i = 0; i < _initial; ++i) { - Signal(); - } if (_sem != nullptr) { dispatch_release(reinterpret_cast(_sem)); _sem = nullptr; @@ -45,7 +42,6 @@ class PlatformSemaphore { private: dispatch_semaphore_t _sem; - const uint32_t _initial; FXL_DISALLOW_COPY_AND_ASSIGN(PlatformSemaphore); }; diff --git a/testing/BUILD.gn b/testing/BUILD.gn index a65311bfaeb7c..3927e71cfc0e4 100644 --- a/testing/BUILD.gn +++ b/testing/BUILD.gn @@ -9,13 +9,9 @@ source_set("testing") { "$flutter_root/testing/run_all_unittests.cc", "$flutter_root/testing/testing.cc", "$flutter_root/testing/testing.h", - "$flutter_root/testing/thread_test.cc", - "$flutter_root/testing/thread_test.h", ] public_deps = [ - "$flutter_root/fml", - "//garnet/public/lib/fxl", "//third_party/googletest:gtest", ] diff --git a/testing/thread_test.cc b/testing/thread_test.cc deleted file mode 100644 index 1306f37678fbe..0000000000000 --- a/testing/thread_test.cc +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2017 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. - -#define FML_USED_ON_EMBEDDER - -#include "flutter/testing/thread_test.h" - -namespace testing { - -void ThreadTest::SetUp() { - thread_ = std::make_unique(); - thread_task_runner_ = thread_->GetTaskRunner(); - - fml::MessageLoop::EnsureInitializedForCurrentThread(); - current_task_runner_ = fml::MessageLoop::GetCurrent().GetTaskRunner(); -} - -void ThreadTest::TearDown() { - thread_task_runner_ = nullptr; - thread_ = nullptr; - current_task_runner_ = nullptr; -} - -fxl::RefPtr ThreadTest::GetCurrentTaskRunner() { - return current_task_runner_; -} - -fxl::RefPtr ThreadTest::GetThreadTaskRunner() { - return thread_task_runner_; -} - -} // namespace testing diff --git a/testing/thread_test.h b/testing/thread_test.h deleted file mode 100644 index 511d09c978858..0000000000000 --- a/testing/thread_test.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2017 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_TESTING_THREAD_TEST_H_ -#define FLUTTER_TESTING_THREAD_TEST_H_ - -#include - -#include "flutter/fml/message_loop.h" -#include "flutter/fml/task_runner.h" -#include "flutter/fml/thread.h" -#include "gtest/gtest.h" -#include "lib/fxl/macros.h" - -namespace testing { - -class ThreadTest : public Test { - public: - fxl::RefPtr GetCurrentTaskRunner(); - - fxl::RefPtr GetThreadTaskRunner(); - - protected: - void SetUp() override; - - void TearDown() override; - - private: - std::unique_ptr thread_; - fxl::RefPtr thread_task_runner_; - fxl::RefPtr current_task_runner_; -}; - -} // namespace testing - -#endif // FLUTTER_TESTING_THREAD_TEST_H_ diff --git a/tools/gn b/tools/gn index b4b15f99f1d4f..ea7071ac0a474 100755 --- a/tools/gn +++ b/tools/gn @@ -232,10 +232,6 @@ def main(argv): # On the Mac, also generate Xcode projects for ease of editing. command.append('--ide=xcode') - if sys.platform.startswith('win'): - # On Windows, also generate Visual Studio project for ease of editing. - command.append('--ide=vs') - gn_args = to_command_line(to_gn_args(args)) out_dir = get_out_dir(args) print "gn gen --check in %s" % out_dir diff --git a/travis/licenses_golden/licenses_flutter b/travis/licenses_golden/licenses_flutter index b15c608425095..8749f6880dbf4 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -1059,10 +1059,14 @@ USED LICENSES: ==================================================================================================== LIBRARY: engine LIBRARY: txt -ORIGIN: ../../../flutter/content_handler/session_connection.cc + ../../../LICENSE +ORIGIN: ../../../flutter/content_handler/service_protocol_hooks.cc + ../../../LICENSE TYPE: LicenseType.bsd +FILE: ../../../flutter/content_handler/service_protocol_hooks.cc +FILE: ../../../flutter/content_handler/service_protocol_hooks.h FILE: ../../../flutter/content_handler/session_connection.cc FILE: ../../../flutter/content_handler/session_connection.h +FILE: ../../../flutter/content_handler/vulkan_rasterizer.cc +FILE: ../../../flutter/content_handler/vulkan_rasterizer.h FILE: ../../../flutter/content_handler/vulkan_surface_producer.cc FILE: ../../../flutter/content_handler/vulkan_surface_producer.h FILE: ../../../flutter/flow/debug_print.cc @@ -1122,6 +1126,7 @@ FILE: ../../../flutter/fml/platform/win/mapping_win.cc FILE: ../../../flutter/fml/platform/win/message_loop_win.cc FILE: ../../../flutter/fml/platform/win/message_loop_win.h FILE: ../../../flutter/fml/platform/win/paths_win.cc +FILE: ../../../flutter/fml/task_observer.h FILE: ../../../flutter/fml/task_runner.cc FILE: ../../../flutter/fml/task_runner.h FILE: ../../../flutter/fml/thread.cc @@ -1137,10 +1142,13 @@ FILE: ../../../flutter/lib/ui/painting/codec.cc FILE: ../../../flutter/lib/ui/painting/codec.h FILE: ../../../flutter/lib/ui/painting/frame_info.cc FILE: ../../../flutter/lib/ui/painting/frame_info.h +FILE: ../../../flutter/lib/ui/painting/utils.cc FILE: ../../../flutter/lib/ui/painting/vertices.cc FILE: ../../../flutter/lib/ui/painting/vertices.h FILE: ../../../flutter/lib/ui/text/font_collection.cc FILE: ../../../flutter/lib/ui/text/font_collection.h +FILE: ../../../flutter/shell/common/null_platform_view.cc +FILE: ../../../flutter/shell/common/null_platform_view.h FILE: ../../../flutter/shell/gpu/gpu_surface_software.cc FILE: ../../../flutter/shell/gpu/gpu_surface_software.h FILE: ../../../flutter/shell/platform/android/android_external_texture_gl.cc @@ -1187,6 +1195,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterStandar FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterStandardCodec_Internal.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterUmbrellaImport.m FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_codecs_unittest.mm +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/flutter_standard_codec_unittest.mm FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.h FILE: ../../../flutter/shell/platform/darwin/ios/ios_external_texture_gl.mm @@ -1553,6 +1563,7 @@ FILE: ../../../flutter/shell/common/skia_event_tracer_impl.cc FILE: ../../../flutter/shell/platform/android/apk_asset_provider.cc FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/common/JSONUtil.java FILE: ../../../flutter/shell/platform/darwin/desktop/Info.plist +FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_mac.xib FILE: ../../../flutter/shell/platform/darwin/ios/framework/Flutter.podspec FILE: ../../../flutter/shell/platform/darwin/ios/framework/Info.plist FILE: ../../../flutter/shell/platform/darwin/ios/framework/module.modulemap @@ -1627,48 +1638,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: engine -ORIGIN: ../../../flutter/assets/asset_manager.cc + ../../../LICENSE +ORIGIN: ../../../flutter/assets/asset_provider.h + ../../../LICENSE TYPE: LicenseType.bsd -FILE: ../../../flutter/assets/asset_manager.cc -FILE: ../../../flutter/assets/asset_manager.h -FILE: ../../../flutter/assets/asset_resolver.h -FILE: ../../../flutter/common/task_runners.cc -FILE: ../../../flutter/common/task_runners.h -FILE: ../../../flutter/flow/layers/default_layer_builder.cc -FILE: ../../../flutter/flow/layers/default_layer_builder.h -FILE: ../../../flutter/flow/layers/layer_builder.cc -FILE: ../../../flutter/flow/layers/layer_builder.h -FILE: ../../../flutter/flow/skia_gpu_object.cc -FILE: ../../../flutter/flow/skia_gpu_object.h -FILE: ../../../flutter/runtime/dart_isolate.cc -FILE: ../../../flutter/runtime/dart_isolate.h -FILE: ../../../flutter/runtime/dart_isolate_unittests.cc -FILE: ../../../flutter/runtime/dart_snapshot.cc -FILE: ../../../flutter/runtime/dart_snapshot.h -FILE: ../../../flutter/runtime/dart_snapshot_buffer.cc -FILE: ../../../flutter/runtime/dart_snapshot_buffer.h -FILE: ../../../flutter/runtime/dart_vm.cc -FILE: ../../../flutter/runtime/dart_vm.h -FILE: ../../../flutter/runtime/dart_vm_unittests.cc -FILE: ../../../flutter/runtime/service_protocol.cc -FILE: ../../../flutter/runtime/service_protocol.h -FILE: ../../../flutter/shell/common/io_manager.cc -FILE: ../../../flutter/shell/common/io_manager.h -FILE: ../../../flutter/shell/common/run_configuration.cc -FILE: ../../../flutter/shell/common/run_configuration.h -FILE: ../../../flutter/shell/common/shell_unittests.cc -FILE: ../../../flutter/shell/common/thread_host.cc -FILE: ../../../flutter/shell/common/thread_host.h -FILE: ../../../flutter/shell/platform/darwin/common/command_line.h -FILE: ../../../flutter/shell/platform/darwin/common/command_line.mm -FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_application_delegate.h -FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_application_delegate.mm -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h -FILE: ../../../flutter/shell/platform/embedder/embedder.h -FILE: ../../../flutter/shell/platform/embedder/embedder_engine.cc -FILE: ../../../flutter/shell/platform/embedder/embedder_engine.h +FILE: ../../../flutter/assets/asset_provider.h +FILE: ../../../flutter/flutter_kernel_transformers/lib/track_widget_constructor_locations.dart +FILE: ../../../flutter/lib/ui/painting/image_encoding.cc +FILE: ../../../flutter/lib/ui/painting/image_encoding.h +FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm ---------------------------------------------------------------------------------------------------- -Copyright 2017 The Flutter Authors. All rights reserved. +Copyright 2018 The Chromium Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -1703,10 +1683,23 @@ ORIGIN: ../../../flutter/assets/directory_asset_bundle.cc + ../../../LICENSE TYPE: LicenseType.bsd FILE: ../../../flutter/assets/directory_asset_bundle.cc FILE: ../../../flutter/assets/directory_asset_bundle.h +FILE: ../../../flutter/assets/unzipper_provider.cc +FILE: ../../../flutter/assets/unzipper_provider.h FILE: ../../../flutter/assets/zip_asset_store.cc FILE: ../../../flutter/assets/zip_asset_store.h FILE: ../../../flutter/common/settings.cc FILE: ../../../flutter/common/settings.h +FILE: ../../../flutter/common/threads.cc +FILE: ../../../flutter/common/threads.h +FILE: ../../../flutter/content_handler/app.cc +FILE: ../../../flutter/content_handler/app.h +FILE: ../../../flutter/content_handler/application_controller_impl.cc +FILE: ../../../flutter/content_handler/application_controller_impl.h +FILE: ../../../flutter/content_handler/main.cc +FILE: ../../../flutter/content_handler/rasterizer.cc +FILE: ../../../flutter/content_handler/rasterizer.h +FILE: ../../../flutter/content_handler/runtime_holder.cc +FILE: ../../../flutter/content_handler/runtime_holder.h FILE: ../../../flutter/flow/export_node.cc FILE: ../../../flutter/flow/layers/backdrop_filter_layer.cc FILE: ../../../flutter/flow/layers/backdrop_filter_layer.h @@ -1714,6 +1707,7 @@ FILE: ../../../flutter/flow/layers/child_scene_layer.cc FILE: ../../../flutter/flow/layers/child_scene_layer.h FILE: ../../../flutter/flow/layers/shader_mask_layer.cc FILE: ../../../flutter/flow/layers/shader_mask_layer.h +FILE: ../../../flutter/flow/process_info.h FILE: ../../../flutter/flow/raster_cache.cc FILE: ../../../flutter/flow/raster_cache.h FILE: ../../../flutter/flow/scene_update_context.cc @@ -1724,6 +1718,9 @@ FILE: ../../../flutter/glue/stack_trace_fuchsia.cc FILE: ../../../flutter/glue/trace_event.h FILE: ../../../flutter/lib/ui/painting/image_filter.cc FILE: ../../../flutter/lib/ui/painting/image_filter.h +FILE: ../../../flutter/lib/ui/painting/resource_context.cc +FILE: ../../../flutter/lib/ui/painting/resource_context.h +FILE: ../../../flutter/lib/ui/painting/utils.h FILE: ../../../flutter/lib/ui/semantics.dart FILE: ../../../flutter/lib/ui/semantics/semantics_node.cc FILE: ../../../flutter/lib/ui/semantics/semantics_node.h @@ -1745,13 +1742,18 @@ FILE: ../../../flutter/runtime/asset_font_selector.cc FILE: ../../../flutter/runtime/asset_font_selector.h FILE: ../../../flutter/runtime/embedder_resources.cc FILE: ../../../flutter/runtime/embedder_resources.h -FILE: ../../../flutter/runtime/fixtures/simple_main.dart +FILE: ../../../flutter/runtime/runtime_init.cc +FILE: ../../../flutter/runtime/runtime_init.h FILE: ../../../flutter/runtime/start_up.cc FILE: ../../../flutter/runtime/start_up.h FILE: ../../../flutter/runtime/test_font_data.cc FILE: ../../../flutter/runtime/test_font_data.h FILE: ../../../flutter/runtime/test_font_selector.cc FILE: ../../../flutter/runtime/test_font_selector.h +FILE: ../../../flutter/shell/common/null_rasterizer.cc +FILE: ../../../flutter/shell/common/null_rasterizer.h +FILE: ../../../flutter/shell/common/platform_view_service_protocol.cc +FILE: ../../../flutter/shell/common/platform_view_service_protocol.h FILE: ../../../flutter/shell/common/skia_event_tracer_impl.h FILE: ../../../flutter/shell/common/surface.cc FILE: ../../../flutter/shell/common/surface.h @@ -1780,6 +1782,8 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.cc FILE: ../../../flutter/shell/platform/android/vsync_waiter_android.h FILE: ../../../flutter/shell/platform/darwin/common/buffer_conversions.mm +FILE: ../../../flutter/shell/platform/darwin/common/process_info_mac.cc +FILE: ../../../flutter/shell/platform/darwin/common/process_info_mac.h FILE: ../../../flutter/shell/platform/darwin/desktop/vsync_waiter_mac.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/Flutter.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterAppDelegate.h @@ -1788,6 +1792,8 @@ FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterMacros FILE: ../../../flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h +FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformPlugin.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterTextInputDelegate.h @@ -1810,6 +1816,7 @@ FILE: ../../../flutter/sky/engine/platform/text/ICUError.cpp FILE: ../../../flutter/sky/engine/platform/text/ICUError.h FILE: ../../../flutter/sky/engine/platform/text/TextBox.h FILE: ../../../flutter/sky/packages/flutter_services/lib/empty.dart +FILE: ../../../flutter/synchronization/debug_thread_checker.h FILE: ../../../flutter/synchronization/pipeline.cc FILE: ../../../flutter/synchronization/pipeline.h FILE: ../../../flutter/synchronization/semaphore.cc @@ -1877,68 +1884,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: engine -ORIGIN: ../../../flutter/content_handler/application.cc + ../../../garnet/LICENSE -TYPE: LicenseType.bsd -FILE: ../../../flutter/content_handler/application.cc -FILE: ../../../flutter/content_handler/application.h -FILE: ../../../flutter/content_handler/application_runner.cc -FILE: ../../../flutter/content_handler/application_runner.h -FILE: ../../../flutter/content_handler/compositor_context.cc -FILE: ../../../flutter/content_handler/compositor_context.h -FILE: ../../../flutter/content_handler/engine.cc -FILE: ../../../flutter/content_handler/engine.h -FILE: ../../../flutter/content_handler/isolate_configurator.cc -FILE: ../../../flutter/content_handler/isolate_configurator.h -FILE: ../../../flutter/content_handler/main.cc -FILE: ../../../flutter/content_handler/platform_view.cc -FILE: ../../../flutter/content_handler/platform_view.h -FILE: ../../../flutter/content_handler/surface.cc -FILE: ../../../flutter/content_handler/surface.h -FILE: ../../../flutter/content_handler/task_observers.cc -FILE: ../../../flutter/content_handler/task_observers.h -FILE: ../../../flutter/content_handler/unique_fdio_ns.h ----------------------------------------------------------------------------------------------------- -Copyright 2018 The Fuchsia Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -==================================================================================================== - -==================================================================================================== -LIBRARY: engine -ORIGIN: ../../../flutter/flutter_kernel_transformers/lib/track_widget_constructor_locations.dart + ../../../LICENSE +ORIGIN: ../../../flutter/flow/layers/default_layer_builder.cc + ../../../LICENSE TYPE: LicenseType.bsd -FILE: ../../../flutter/flutter_kernel_transformers/lib/track_widget_constructor_locations.dart -FILE: ../../../flutter/lib/ui/painting/image_encoding.cc -FILE: ../../../flutter/lib/ui/painting/image_encoding.h -FILE: ../../../flutter/shell/platform/android/apk_asset_provider.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/accessibility_text_entry.mm +FILE: ../../../flutter/flow/layers/default_layer_builder.cc +FILE: ../../../flutter/flow/layers/default_layer_builder.h +FILE: ../../../flutter/flow/layers/layer_builder.cc +FILE: ../../../flutter/flow/layers/layer_builder.h +FILE: ../../../flutter/shell/platform/embedder/embedder.h ---------------------------------------------------------------------------------------------------- -Copyright 2018 The Chromium Authors. All rights reserved. +Copyright 2017 The Flutter Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -2003,62 +1957,6 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== -==================================================================================================== -LIBRARY: engine -ORIGIN: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc + ../../../LICENSE -TYPE: LicenseType.bsd -FILE: ../../../flutter/fml/file.h -FILE: ../../../flutter/fml/macros.h -FILE: ../../../flutter/fml/mapping.cc -FILE: ../../../flutter/fml/native_library.h -FILE: ../../../flutter/fml/paths.cc -FILE: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc -FILE: ../../../flutter/fml/platform/posix/file_posix.cc -FILE: ../../../flutter/fml/platform/posix/native_library_posix.cc -FILE: ../../../flutter/fml/platform/win/file_win.cc -FILE: ../../../flutter/fml/platform/win/native_library_win.cc -FILE: ../../../flutter/fml/platform/win/wstring_conversion.h -FILE: ../../../flutter/fml/unique_fd.cc -FILE: ../../../flutter/fml/unique_fd.h -FILE: ../../../flutter/fml/unique_object.h -FILE: ../../../flutter/shell/common/isolate_configuration.cc -FILE: ../../../flutter/shell/common/isolate_configuration.h -FILE: ../../../flutter/shell/platform/android/android_shell_holder.cc -FILE: ../../../flutter/shell/platform/android/android_shell_holder.h -FILE: ../../../flutter/shell/platform/android/platform_message_response_android.cc -FILE: ../../../flutter/shell/platform/android/platform_message_response_android.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h -FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm ----------------------------------------------------------------------------------------------------- -Copyright 2018 The Flutter Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -==================================================================================================== - ==================================================================================================== LIBRARY: engine ORIGIN: ../../../flutter/lib/ui/painting/image.cc + ../../../LICENSE @@ -9975,6 +9873,10 @@ FILE: ../../../flutter/lib/ui/window.dart FILE: ../../../flutter/lib/ui/window/pointer_data.cc FILE: ../../../flutter/lib/ui/window/pointer_data_packet.cc FILE: ../../../flutter/lib/ui/window/window.cc +FILE: ../../../flutter/runtime/dart_controller.cc +FILE: ../../../flutter/runtime/dart_controller.h +FILE: ../../../flutter/runtime/dart_init.cc +FILE: ../../../flutter/runtime/dart_init.h FILE: ../../../flutter/runtime/dart_service_isolate.cc FILE: ../../../flutter/runtime/dart_service_isolate.h FILE: ../../../flutter/runtime/platform_impl.cc @@ -9994,9 +9896,13 @@ FILE: ../../../flutter/shell/common/rasterizer.cc FILE: ../../../flutter/shell/common/rasterizer.h FILE: ../../../flutter/shell/common/shell.cc FILE: ../../../flutter/shell/common/shell.h +FILE: ../../../flutter/shell/common/tracing_controller.cc +FILE: ../../../flutter/shell/common/tracing_controller.h FILE: ../../../flutter/shell/common/vsync_waiter.cc FILE: ../../../flutter/shell/common/vsync_waiter.h FILE: ../../../flutter/shell/common/vsync_waiter_fallback.h +FILE: ../../../flutter/shell/gpu/gpu_rasterizer.cc +FILE: ../../../flutter/shell/gpu/gpu_rasterizer.h FILE: ../../../flutter/shell/platform/android/AndroidManifest.xml FILE: ../../../flutter/shell/platform/android/flutter_main.cc FILE: ../../../flutter/shell/platform/android/flutter_main.h @@ -10009,6 +9915,12 @@ FILE: ../../../flutter/shell/platform/android/library_loader.cc FILE: ../../../flutter/shell/platform/android/platform_view_android.cc FILE: ../../../flutter/shell/platform/android/platform_view_android.h FILE: ../../../flutter/shell/platform/darwin/common/buffer_conversions.h +FILE: ../../../flutter/shell/platform/darwin/common/platform_mac.h +FILE: ../../../flutter/shell/platform/darwin/common/platform_mac.mm +FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_app_delegate.h +FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_app_delegate.m +FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_application.h +FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_application.mm FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_window.h FILE: ../../../flutter/shell/platform/darwin/desktop/flutter_window.mm FILE: ../../../flutter/shell/platform/darwin/desktop/main_mac.mm @@ -10018,6 +9930,8 @@ FILE: ../../../flutter/shell/platform/darwin/desktop/vsync_waiter_mac.cc FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/FlutterAppDelegate.mm FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h FILE: ../../../flutter/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +FILE: ../../../flutter/shell/platform/linux/main_linux.cc +FILE: ../../../flutter/shell/platform/win/main_win.cc FILE: ../../../flutter/sky/engine/wtf/Allocator.h FILE: ../../../flutter/sky/engine/wtf/MakeUnique.h ---------------------------------------------------------------------------------------------------- @@ -10054,7 +9968,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIBRARY: engine ORIGIN: ../../../topaz/LICENSE TYPE: LicenseType.bsd -FILE: ../../../flutter/fml/memory/thread_checker.h FILE: ../../../flutter/fml/memory/weak_ptr.h FILE: ../../../flutter/fml/memory/weak_ptr_internal.cc FILE: ../../../flutter/fml/memory/weak_ptr_internal.h @@ -10088,4 +10001,4 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== -Total license count: 218 +Total license count: 216