diff --git a/BUILD.gn b/BUILD.gn index 24dda026c6245ed30db5e3823c8e0015356a45fe..b37b0b8d4054c8d2811d3fb9e32a75ddf8249fa0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -10,14 +10,12 @@ 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) { @@ -45,20 +43,24 @@ 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", + ] + } } } @@ -74,29 +76,23 @@ 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") { @@ -104,29 +100,23 @@ 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 f771a4be4088be8537b8e91e35454ebc519ff122..d7f022879b66c9cac63a16cf8aa675d9bba0ce90 100644 --- a/DEPS +++ b/DEPS @@ -115,7 +115,7 @@ allowed_hosts = [ ] deps = { - 'src': 'https://github.com/flutter/buildroot.git' + '@' + '8dddd90bf943a8174913564353b30a3b11ee0f7a', + 'src': 'https://github.com/flutter/buildroot.git' + '@' + '3cf97e01cdbd4bb920fa3d40282a56c4b2d62a58', # Fuchsia compatibility # diff --git a/assets/BUILD.gn b/assets/BUILD.gn index c4901375ad8106c894590f3d327962cb5a8acce5..28d7e569659f15026c8c52fa6cd765a44cd506ae 100644 --- a/assets/BUILD.gn +++ b/assets/BUILD.gn @@ -4,16 +4,18 @@ source_set("assets") { sources = [ - "asset_provider.h", + "asset_manager.cc", + "asset_manager.h", + "asset_resolver.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", @@ -23,7 +25,5 @@ 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 new file mode 100644 index 0000000000000000000000000000000000000000..9833eee9232571e7deaa447e58d889ca29854ab5 --- /dev/null +++ b/assets/asset_manager.cc @@ -0,0 +1,59 @@ +// 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" + +#ifdef ERROR +#undef ERROR +#endif + +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 new file mode 100644 index 0000000000000000000000000000000000000000..fc7f3ef05210e87d9083027d1667d966089f1bcf --- /dev/null +++ b/assets/asset_manager.h @@ -0,0 +1,47 @@ +// 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 deleted file mode 100644 index 68b7f5c2b7b9c94bef9131322b1d5cf7c3799481..0000000000000000000000000000000000000000 --- a/assets/asset_provider.h +++ /dev/null @@ -1,25 +0,0 @@ -// 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 new file mode 100644 index 0000000000000000000000000000000000000000..6cfe27961a9f49d79cc96b4bbab299c5a0ff066e --- /dev/null +++ b/assets/asset_resolver.h @@ -0,0 +1,32 @@ +// 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 43933079a81bd03ddb0199ea0461957d46173d3a..8e5d4df2ab977b1e3696a6ced1795e7506a8126c 100644 --- a/assets/directory_asset_bundle.cc +++ b/assets/directory_asset_bundle.cc @@ -3,73 +3,54 @@ // 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 { -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; - - 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); +DirectoryAssetBundle::DirectoryAssetBundle(fml::UniqueFD descriptor) + : descriptor_(std::move(descriptor)) { + if (!fml::IsDirectory(descriptor_)) { + return; + } + is_valid_ = true; +} - if (bytes_read < 0) { - FXL_LOG(ERROR) << "Reading " << asset_name << " failed"; - data->clear(); - return false; - } +DirectoryAssetBundle::~DirectoryAssetBundle() = default; - data->resize(offset + bytes_read); - return true; -#endif - } - std::string asset_path = GetPathForAsset(asset_name); - if (asset_path.empty()) - return false; - return files::ReadFileToVector(asset_path, data); +// |blink::AssetResolver| +bool DirectoryAssetBundle::IsValid() const { + return is_valid_; } -DirectoryAssetBundle::~DirectoryAssetBundle() {} +// |blink::AssetResolver| +bool DirectoryAssetBundle::GetAsBuffer(const std::string& asset_name, + std::vector* data) const { + if (data == nullptr) { + return false; + } -DirectoryAssetBundle::DirectoryAssetBundle(std::string directory) - : directory_(std::move(directory)), fd_() {} + if (!is_valid_) { + FXL_DLOG(WARNING) << "Asset bundle was not valid."; + return false; + } -DirectoryAssetBundle::DirectoryAssetBundle(fxl::UniqueFD fd) - : fd_(std::move(fd)) {} + fml::FileMapping mapping( + fml::OpenFile(descriptor_, asset_name.c_str(), fml::OpenPermission::kRead, + false /* directory */), + false /* executable */); -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(); + if (mapping.GetMapping() == nullptr) { + return false; } - return asset_path; + + data->resize(mapping.GetSize()); + memmove(data->data(), mapping.GetMapping(), mapping.GetSize()); + return true; } } // namespace blink diff --git a/assets/directory_asset_bundle.h b/assets/directory_asset_bundle.h index c710a513796ae9894bfd9b148464d0e96e47fac5..b594e1357fbe2aa012268987bbaa20adc22888ed 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 -#include - -#include "flutter/assets/asset_provider.h" -#include "lib/fxl/files/unique_fd.h" +#include "flutter/assets/asset_resolver.h" +#include "flutter/fml/unique_fd.h" #include "lib/fxl/macros.h" #include "lib/fxl/memory/ref_counted.h" namespace blink { -class DirectoryAssetBundle - : public AssetProvider { +class DirectoryAssetBundle : public AssetResolver { public: - explicit DirectoryAssetBundle(std::string directory); - // Expects fd to be valid, otherwise the file descriptor is ignored. - explicit DirectoryAssetBundle(fxl::UniqueFD fd); - virtual ~DirectoryAssetBundle(); - - virtual bool GetAsBuffer(const std::string& asset_name, std::vector* data); + explicit DirectoryAssetBundle(fml::UniqueFD descriptor); - std::string GetPathForAsset(const std::string& asset_name); + ~DirectoryAssetBundle() override; private: - const std::string directory_; - fxl::UniqueFD fd_; + const fml::UniqueFD descriptor_; + bool is_valid_ = false; + + std::string GetPathForAsset(const std::string& asset_name) const; + + // |blink::AssetResolver| + bool IsValid() const override; + + // |blink::AssetResolver| + bool GetAsBuffer(const std::string& asset_name, + std::vector* data) const override; FXL_DISALLOW_COPY_AND_ASSIGN(DirectoryAssetBundle); }; diff --git a/assets/unzipper_provider.cc b/assets/unzipper_provider.cc deleted file mode 100644 index 8ed023f9a20e9fbd064a2ec6d78f559268ec8a1c..0000000000000000000000000000000000000000 --- a/assets/unzipper_provider.cc +++ /dev/null @@ -1,21 +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. - -#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 deleted file mode 100644 index f0f8d9597dffdbed7f3081eadd5b6ae5780aaf02..0000000000000000000000000000000000000000 --- a/assets/unzipper_provider.h +++ /dev/null @@ -1,20 +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. - -#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 c8534fa10c2168d37eec54ed0f1bae05c4392e8f..1b9216bd34530ec1d6408e6a1ca8aea55f266faa 100644 --- a/assets/zip_asset_store.cc +++ b/assets/zip_asset_store.cc @@ -15,21 +15,28 @@ #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(UnzipperProvider unzipper_provider) - : unzipper_provider_(std::move(unzipper_provider)) { +ZipAssetStore::ZipAssetStore(std::string file_path) + : file_path_(std::move(file_path)) { 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) { + std::vector* data) const { TRACE_EVENT0("flutter", "ZipAssetStore::GetAsBuffer"); auto found = stat_cache_.find(asset_name); @@ -37,7 +44,7 @@ bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, return false; } - auto unzipper = unzipper_provider_(); + auto unzipper = CreateUnzipper(); if (!unzipper.is_valid()) { return false; @@ -73,7 +80,8 @@ bool ZipAssetStore::GetAsBuffer(const std::string& asset_name, void ZipAssetStore::BuildStatCache() { TRACE_EVENT0("flutter", "ZipAssetStore::BuildStatCache"); - auto unzipper = unzipper_provider_(); + + auto unzipper = CreateUnzipper(); if (!unzipper.is_valid()) { return; diff --git a/assets/zip_asset_store.h b/assets/zip_asset_store.h index 1ffda483ba9b7dc65d4f589f5fab240e47b41dce..558678e25bc08f8ac3f7f3780d3730fc2e09b893 100644 --- a/assets/zip_asset_store.h +++ b/assets/zip_asset_store.h @@ -6,21 +6,20 @@ #define FLUTTER_ASSETS_ZIP_ASSET_STORE_H_ #include -#include -#include "flutter/assets/unzipper_provider.h" +#include "flutter/assets/asset_resolver.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 : public fxl::RefCountedThreadSafe { +class ZipAssetStore final : public AssetResolver { public: - explicit ZipAssetStore(UnzipperProvider unzipper_provider); - ~ZipAssetStore(); + ZipAssetStore(std::string file_path); - bool GetAsBuffer(const std::string& asset_name, std::vector* data); + ~ZipAssetStore() override; private: struct CacheEntry { @@ -30,11 +29,20 @@ class ZipAssetStore : public fxl::RefCountedThreadSafe { : file_pos(p_file_pos), uncompressed_size(p_uncompressed_size) {} }; - UnzipperProvider unzipper_provider_; - std::map stat_cache_; + 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; void BuildStatCache(); + zip::UniqueUnzipper CreateUnzipper() const; + FXL_DISALLOW_COPY_AND_ASSIGN(ZipAssetStore); }; diff --git a/common/BUILD.gn b/common/BUILD.gn index 53b71914d49d131fa1806d768d0458cc0f5b70b2..47cd7d3d626446d722b558bde8befd1010f35b28 100644 --- a/common/BUILD.gn +++ b/common/BUILD.gn @@ -12,11 +12,12 @@ source_set("common") { sources = [ "settings.cc", "settings.h", - "threads.cc", - "threads.h", + "task_runners.cc", + "task_runners.h", ] deps = [ + "$flutter_root/fml", "//garnet/public/lib/fxl", ] diff --git a/common/settings.cc b/common/settings.cc index 0198f714cbaadd826b441ffd771cb3ed15f8e1fb..85523e1b9a29f95b300c6dda2db565da05b7d6ab 100644 --- a/common/settings.cc +++ b/common/settings.cc @@ -4,26 +4,50 @@ #include "flutter/common/settings.h" -#include - -#include "lib/fxl/logging.h" +#include namespace blink { -namespace { - -Settings* g_settings = nullptr; - -} // namespace - -const Settings& Settings::Get() { - FXL_CHECK(g_settings); - return *g_settings; -} -void Settings::Set(const Settings& settings) { - FXL_CHECK(!g_settings); - g_settings = new Settings(); - *g_settings = 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(); } } // namespace blink diff --git a/common/settings.h b/common/settings.h index 5bb5c6cbbea42bdcb622bd334f355f70f3b94bc9..c6c3159766a3779788e9a1b05dc17b33949649e9 100644 --- a/common/settings.h +++ b/common/settings.h @@ -5,40 +5,82 @@ #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 { - 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; + // VM settings + std::string script_snapshot_path; + std::string kernel_snapshot_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; - static const Settings& Get(); - static void Set(const Settings& settings); + std::string ToString() const; }; } // namespace blink diff --git a/common/task_runners.cc b/common/task_runners.cc new file mode 100644 index 0000000000000000000000000000000000000000..1a09daec1815c14e48f7d4edf14d8f6469f8ad16 --- /dev/null +++ b/common/task_runners.cc @@ -0,0 +1,48 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..f41ae147ebad0765176dac007fdd90c328b9250e --- /dev/null +++ b/common/task_runners.h @@ -0,0 +1,46 @@ +// 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 deleted file mode 100644 index 3634d8d7c87234e92f7cc13c14e3ed164202492a..0000000000000000000000000000000000000000 --- a/common/threads.cc +++ /dev/null @@ -1,56 +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. - -#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 deleted file mode 100644 index 456a5eba8ad9760937cd67ca83a6b5ed00615f4f..0000000000000000000000000000000000000000 --- a/common/threads.h +++ /dev/null @@ -1,48 +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. - -#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 6bc00b4e2786cf0764783e37a87e7d880e31a1ed..4778784baa643273e0d328d88b8db82913f436d0 100644 --- a/content_handler/BUILD.gn +++ b/content_handler/BUILD.gn @@ -20,23 +20,28 @@ template("flutter_content_handler") { sources = [ "accessibility_bridge.cc", "accessibility_bridge.h", - "app.cc", - "app.h", - "application_controller_impl.cc", - "application_controller_impl.h", + "application.cc", + "application.h", + "application_runner.cc", + "application_runner.h", + "compositor_context.cc", + "compositor_context.h", + "engine.cc", + "engine.h", "fuchsia_font_manager.cc", "fuchsia_font_manager.h", + "isolate_configurator.cc", + "isolate_configurator.h", "main.cc", - "rasterizer.cc", - "rasterizer.h", - "runtime_holder.cc", - "runtime_holder.h", - "service_protocol_hooks.cc", - "service_protocol_hooks.h", + "platform_view.cc", + "platform_view.h", "session_connection.cc", "session_connection.h", - "vulkan_rasterizer.cc", - "vulkan_rasterizer.h", + "surface.cc", + "surface.h", + "task_observers.cc", + "task_observers.h", + "unique_fdio_ns.h", "vulkan_surface.cc", "vulkan_surface.h", "vulkan_surface_pool.cc", @@ -45,18 +50,26 @@ 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", @@ -73,8 +86,10 @@ 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 + ] + extra_deps + flutter_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 new file mode 100644 index 0000000000000000000000000000000000000000..4461e808d1a47fbc01a09beaa1c75e782d06b39a --- /dev/null +++ b/content_handler/README.md @@ -0,0 +1,4 @@ +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 cb6f9b8e21155da8d2626f9b9902ebee93fc52c4..f3d52f6cdbbb693d7b877769f14051e88ce79cca 100644 --- a/content_handler/accessibility_bridge.cc +++ b/content_handler/accessibility_bridge.cc @@ -2,21 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/content_handler/accessibility_bridge.h" +#include "accessibility_bridge.h" #include -#include "flutter/lib/ui/semantics/semantics_node.h" #include "lib/app/cpp/application_context.h" -#include "lib/fxl/macros.h" +#include "lib/context/fidl/context_writer.fidl.h" #include "third_party/rapidjson/rapidjson/document.h" #include "third_party/rapidjson/rapidjson/stringbuffer.h" #include "third_party/rapidjson/rapidjson/writer.h" -namespace flutter_runner { +namespace flutter { -AccessibilityBridge::AccessibilityBridge(component::ApplicationContext* context) - : writer_(context->ConnectToEnvironmentService()) {} +AccessibilityBridge::AccessibilityBridge(maxwell::ContextWriterPtr writer) + : writer_(std::move(writer)) {} + +AccessibilityBridge::~AccessibilityBridge() = default; void AccessibilityBridge::UpdateSemantics( const blink::SemanticsNodeUpdates& update) { @@ -77,4 +78,4 @@ void AccessibilityBridge::EraseUnvisitedNodes( } } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/accessibility_bridge.h b/content_handler/accessibility_bridge.h index 7ac54e754d9b6cc4ed5e710058d758fae75afca8..dde8bfaa54c3654cd3f5fbb5aa0db5e5db50940e 100644 --- a/content_handler/accessibility_bridge.h +++ b/content_handler/accessibility_bridge.h @@ -2,28 +2,32 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_CONTENT_HANDLER_ACCESSIBILITY_BRIDGE_H_ -#define FLUTTER_CONTENT_HANDLER_ACCESSIBILITY_BRIDGE_H_ +#pragma once #include #include "flutter/lib/ui/semantics/semantics_node.h" -#include "lib/app/cpp/application_context.h" -#include +#include "lib/context/fidl/context_writer.fidl.h" +#include "lib/fxl/macros.h" -namespace flutter_runner { +namespace flutter { // Maintain an up-to-date list of SemanticsNodes on screen, and communicate // with the Context Service. -class AccessibilityBridge { +class AccessibilityBridge final { public: - explicit AccessibilityBridge(component::ApplicationContext* context); + AccessibilityBridge(maxwell::ContextWriterPtr writer); + + ~AccessibilityBridge(); // 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, @@ -33,10 +37,7 @@ class AccessibilityBridge { // |visited_nodes|. void EraseUnvisitedNodes(const std::vector& visited_nodes); - std::map semantics_nodes_; - modular::ContextWriterPtr writer_; + FXL_DISALLOW_COPY_AND_ASSIGN(AccessibilityBridge); }; -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_ACCESSIBILITY_BRIDGE_H_ +} // namespace flutter diff --git a/content_handler/app.cc b/content_handler/app.cc deleted file mode 100644 index 1f1bde833d2f3cf44e58dedfa65a4cb40554c48b..0000000000000000000000000000000000000000 --- a/content_handler/app.cc +++ /dev/null @@ -1,174 +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. - -#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 deleted file mode 100644 index dc8c49927d897dbba0c9c41762cbd33b68216985..0000000000000000000000000000000000000000 --- a/content_handler/app.h +++ /dev/null @@ -1,64 +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. - -#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 new file mode 100644 index 0000000000000000000000000000000000000000..7dd2270d42317cc3a074ea05f46e362d03963138 --- /dev/null +++ b/content_handler/application.cc @@ -0,0 +1,313 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..e4f5da105cac802f7bb41c04690a7c51375e69e3 --- /dev/null +++ b/content_handler/application.h @@ -0,0 +1,97 @@ +// 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 deleted file mode 100644 index 9a1b449138a1bed625b502ab29dee8493d15c5b3..0000000000000000000000000000000000000000 --- a/content_handler/application_controller_impl.cc +++ /dev/null @@ -1,148 +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. - -#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 deleted file mode 100644 index 01700f2886ffb00077b5bce24043dd371f90ddad..0000000000000000000000000000000000000000 --- a/content_handler/application_controller_impl.h +++ /dev/null @@ -1,76 +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. - -#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 new file mode 100644 index 0000000000000000000000000000000000000000..2d77f43cbdd45dbed3eef1b73f2ded7cc68d8914 --- /dev/null +++ b/content_handler/application_runner.cc @@ -0,0 +1,90 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..fdf5b4420dc0f3570f41f688e7bc0f740de76936 --- /dev/null +++ b/content_handler/application_runner.h @@ -0,0 +1,79 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..efad9ac2b95831750f4f5782e7e56e35922fde8a --- /dev/null +++ b/content_handler/compositor_context.cc @@ -0,0 +1,86 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..a6e5429c6072c7fbb7802ddc7e428276cff433fc --- /dev/null +++ b/content_handler/compositor_context.h @@ -0,0 +1,39 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..3349c09bdf1af7d676b1fdd64e65b3d3ea00bfad --- /dev/null +++ b/content_handler/engine.cc @@ -0,0 +1,258 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..60c0ad7c2f80d2f4fcca31c62bc6080fe1fff389 --- /dev/null +++ b/content_handler/engine.h @@ -0,0 +1,63 @@ +// 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 4e409cae94f6acd6f0a757abf93e8de2972033f8..877c931130eb48c8b3b0cc23b5d4952793257bfd 100644 --- a/content_handler/fuchsia_font_manager.cc +++ b/content_handler/fuchsia_font_manager.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "flutter/content_handler/fuchsia_font_manager.h" +#include "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 MakeSkDataFromBuffer(mem::Buffer data) { - if (!fsl::SizedVmo::IsSizeValid(data.vmo, data.size) || - data.size > std::numeric_limits::max()) { +sk_sp MakeSkDataFromVMO(const fsl::SizedVmoTransportPtr& vmo) { + if (!fsl::SizedVmo::IsSizeValid(vmo->vmo, vmo->size) || + vmo->size > std::numeric_limits::max()) { return nullptr; } - uint64_t size = data.size; + uint64_t size = vmo->size; uintptr_t buffer = 0; - zx_status_t status = zx::vmar::root_self().map(0, data.vmo, 0, size, + zx_status_t status = zx::vmar::root_self().map(0, vmo->vmo, 0, size, ZX_VM_FLAG_PERM_READ, &buffer); if (status != ZX_OK) return nullptr; @@ -49,7 +49,7 @@ sk_sp MakeSkDataFromBuffer(mem::Buffer data) { fonts::FontSlant ToFontSlant(SkFontStyle::Slant slant) { return (slant == SkFontStyle::kItalic_Slant) ? fonts::FontSlant::ITALIC - : fonts::FontSlant::UPRIGHT; + : fonts::FontSlant::UPRIGHT; } } // anonymous namespace @@ -64,7 +64,8 @@ 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); } @@ -87,12 +88,13 @@ SkFontStyleSet* FuchsiaFontManager::onMatchFamily( } SkTypeface* FuchsiaFontManager::onMatchFamilyStyle( - 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()); + 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()); fonts::FontResponsePtr response; font_provider_->GetFont( @@ -100,14 +102,13 @@ SkTypeface* FuchsiaFontManager::onMatchFamilyStyle( [&response](fonts::FontResponsePtr r) { response = std::move(r); }); font_provider_.WaitForResponse(); - FXL_DCHECK(response) - << "Unable to contact the font provider. Did you run " - "Flutter in an environment that has a font manager?\n"; - - if (!response) + if (!response) { + FXL_DLOG(ERROR) << "Unable to contact the font provider. Did you run " + "Flutter in an environment that has a font manager?"; return nullptr; + } - sk_sp data = MakeSkDataFromBuffer(std::move(response->data.buffer)); + sk_sp data = MakeSkDataFromVMO(response->data->vmo); if (!data) return nullptr; @@ -127,13 +128,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; } @@ -153,7 +154,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 e57d6ef76e72f5faac5a0a5276a2834686d95abb..ecfb724b858788acb62e06e126a2ffe2a34c8079 100644 --- a/content_handler/fuchsia_font_manager.h +++ b/content_handler/fuchsia_font_manager.h @@ -26,7 +26,7 @@ namespace txt { -class FuchsiaFontManager : public SkFontMgr { +class FuchsiaFontManager final : public SkFontMgr { public: FuchsiaFontManager(fonts::FontProviderPtr provider); diff --git a/content_handler/isolate_configurator.cc b/content_handler/isolate_configurator.cc new file mode 100644 index 0000000000000000000000000000000000000000..d085bea698b9540bbf537d975c369946e6b00326 --- /dev/null +++ b/content_handler/isolate_configurator.cc @@ -0,0 +1,114 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..a5da083633ee76348201902296227bb9bf2fd06a --- /dev/null +++ b/content_handler/isolate_configurator.h @@ -0,0 +1,55 @@ +// 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 d3eac3c81dcbf727b0ec559d630dff44084502be..15b8cede5b9b2ea831998d9cb8ceb304d6ff1a4e 100644 --- a/content_handler/main.cc +++ b/content_handler/main.cc @@ -1,16 +1,26 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. +// 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 +#include -#include "flutter/content_handler/app.h" +#include "application_runner.h" #include "lib/fsl/tasks/message_loop.h" -int main(int argc, const char** argv) { +int main(int argc, char const* argv[]) { fsl::MessageLoop loop; + trace::TraceProvider provider(loop.async()); - flutter_runner::App app; + 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..."; + }); + loop.Run(); - return 0; + + return EXIT_SUCCESS; } diff --git a/content_handler/platform_view.cc b/content_handler/platform_view.cc new file mode 100644 index 0000000000000000000000000000000000000000..8ac41613e449b08d9e3eff2b810bda22c1186e1a --- /dev/null +++ b/content_handler/platform_view.cc @@ -0,0 +1,551 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..9888d061352bbe89bac61529dd3844f597497895 --- /dev/null +++ b/content_handler/platform_view.h @@ -0,0 +1,120 @@ +// 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 deleted file mode 100644 index b720809b17a45916401b3efdbdb9fa622e4b15bc..0000000000000000000000000000000000000000 --- a/content_handler/rasterizer.cc +++ /dev/null @@ -1,19 +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. - -#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 deleted file mode 100644 index 398f262a568cd26a09975ea5a2841748afefb089..0000000000000000000000000000000000000000 --- a/content_handler/rasterizer.h +++ /dev/null @@ -1,35 +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. - -#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 deleted file mode 100644 index 421731b9691d0b776eec9adb7e50d00c73c70faa..0000000000000000000000000000000000000000 --- a/content_handler/runtime_holder.cc +++ /dev/null @@ -1,911 +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. - -#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 deleted file mode 100644 index b9d55d9f9baccf2a1985fd98c84dfaecb16a18d7..0000000000000000000000000000000000000000 --- a/content_handler/runtime_holder.h +++ /dev/null @@ -1,152 +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. - -#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 deleted file mode 100644 index 9a91254f13488d66af568832cfde53a1642b85f2..0000000000000000000000000000000000000000 --- a/content_handler/service_protocol_hooks.cc +++ /dev/null @@ -1,164 +0,0 @@ -// 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 deleted file mode 100644 index 479fb71471f1e0d51121ba1fd9b5cf777e1cabfb..0000000000000000000000000000000000000000 --- a/content_handler/service_protocol_hooks.h +++ /dev/null @@ -1,37 +0,0 @@ -// 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 b496ae37f40f22d53c44062c72da2c37639bc640..870020abb670f5b7630cafaeea34e2c2f785858f 100644 --- a/content_handler/session_connection.cc +++ b/content_handler/session_connection.cc @@ -2,72 +2,69 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "flutter/content_handler/session_connection.h" -#include "lib/fidl/cpp/optional.h" +#include "session_connection.h" + #include "lib/ui/scenic/fidl_helpers.h" -namespace flutter_runner { +namespace flutter { -SessionConnection::SessionConnection(ui::ScenicPtr scenic, - zx::eventpair import_token) - : session_(scenic.get()), +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()), root_node_(&session_), surface_producer_(std::make_unique(&session_)), - scene_update_context_(&session_, surface_producer_.get()) { - ASSERT_IS_GPU_THREAD; - - session_.set_error_handler( - std::bind(&SessionConnection::OnSessionError, this)); + 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)); session_.set_event_handler(std::bind(&SessionConnection::OnSessionEvents, this, std::placeholders::_1)); root_node_.Bind(std::move(import_token)); - root_node_.SetEventMask(gfx::kMetricsEventMask); - session_.Present(0, [](images::PresentationInfo info) {}); - - present_callback_ = - std::bind(&SessionConnection::OnPresent, this, std::placeholders::_1); + root_node_.SetEventMask(ui::gfx::kMetricsEventMask); + session_.Present(0, [](ui::PresentationInfoPtr info) {}); } -SessionConnection::~SessionConnection() { - ASSERT_IS_GPU_THREAD; -} +SessionConnection::~SessionConnection() = default; -void SessionConnection::OnSessionError() { - ASSERT_IS_GPU_THREAD; - // TODO: Not this. - FXL_CHECK(false) << "Session connection was terminated."; -} +void SessionConnection::OnSessionEvents(f1dl::Array events) { + using Type = ui::gfx::Event::Tag; -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; + for (auto& raw_event : *events) { + if (!raw_event->is_gfx()) { + continue; } - } - if (!new_metrics) - return; - scene_update_context_.set_metrics(fidl::MakeOptional(std::move(*new_metrics))); - - if (metrics_changed_callback_) - metrics_changed_callback_(); + 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::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; - +void SessionConnection::Present(flow::CompositorContext::ScopedFrame& frame) { // 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 for now. - present_callback_ // callback + session_.Present(0, // presentation_time. (placeholder). + [](ui::PresentationInfoPtr) {} // callback ); // Execute paint tasks and signal fences. @@ -77,22 +74,15 @@ 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. - EnqueueClearCommands(); -} - -void SessionConnection::OnPresent(images::PresentationInfo info) { - ASSERT_IS_GPU_THREAD; - auto callback = pending_on_present_callback_; - pending_on_present_callback_ = nullptr; - callback(); + // Prepare for the next frame. These ops won't be processed till the next + // present. + EnqueueClearOps(); } -void SessionConnection::EnqueueClearCommands() { - ASSERT_IS_GPU_THREAD; +void SessionConnection::EnqueueClearOps() { // We are going to be sending down a fresh node hierarchy every frame. So just - // enqueue a detach command on the imported root node. + // enqueue a detach op on the imported root node. session_.Enqueue(scenic_lib::NewDetachChildrenCommand(root_node_.id())); } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/session_connection.h b/content_handler/session_connection.h index a80ba3a2235d28a32f32adc75c60ced3a423aa79..e4f39d314c98fc4965bed4a0c9f51cecae401c0d 100644 --- a/content_handler/session_connection.h +++ b/content_handler/session_connection.h @@ -2,70 +2,62 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ -#define FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ +#pragma once #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/interface_handle.h" +#include "lib/fidl/cpp/bindings/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_runner { +namespace flutter { -class SessionConnection { +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 { public: - SessionConnection(ui::ScenicPtr scenic, zx::eventpair import_token); + 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(); bool has_metrics() const { return scene_update_context_.has_metrics(); } - const gfx::MetricsPtr& metrics() const { + const ui::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() { - ASSERT_IS_GPU_THREAD; - return root_node_; - } + scenic_lib::ImportNode& root_node() { return root_node_; } - void Present(flow::CompositorContext::ScopedFrame& frame, - fxl::Closure on_present_callback); + void Present(flow::CompositorContext::ScopedFrame& frame); 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_; - fxl::Closure metrics_changed_callback_; - - void OnSessionError(); - void OnSessionEvents(fidl::VectorPtr events); + OnMetricsUpdate metrics_changed_callback_; - void EnqueueClearCommands(); + void OnSessionEvents(f1dl::Array events); - void OnPresent(images::PresentationInfo info); + void EnqueueClearOps(); FXL_DISALLOW_COPY_AND_ASSIGN(SessionConnection); }; -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_SESSION_CONNECTION_H_ +} // namespace flutter diff --git a/content_handler/surface.cc b/content_handler/surface.cc new file mode 100644 index 0000000000000000000000000000000000000000..8efe1975fbfdb08bb5d2bf039f16c8f7f9c9a07e --- /dev/null +++ b/content_handler/surface.cc @@ -0,0 +1,73 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..4ad27aaf540f3d889773a1b11c0c7e7f138de5d6 --- /dev/null +++ b/content_handler/surface.h @@ -0,0 +1,47 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..f23265e7b1653783c2ba3d7ba9fee889e3cda188 --- /dev/null +++ b/content_handler/task_observers.cc @@ -0,0 +1,43 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..53f6b96222000b04fae72f40bfbeaad1b3740f10 --- /dev/null +++ b/content_handler/task_observers.h @@ -0,0 +1,16 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..726137d729f85a1716a424ba6861c23bcc39ede3 --- /dev/null +++ b/content_handler/unique_fdio_ns.h @@ -0,0 +1,34 @@ +// 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 deleted file mode 100644 index 25f90c460ce3fd8c9295b25472896c11437d56a3..0000000000000000000000000000000000000000 --- a/content_handler/vulkan_rasterizer.cc +++ /dev/null @@ -1,117 +0,0 @@ -// 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 deleted file mode 100644 index c3ae211553f5aae9364cbdaab08251ba68561a4a..0000000000000000000000000000000000000000 --- a/content_handler/vulkan_rasterizer.h +++ /dev/null @@ -1,42 +0,0 @@ -// 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 6d5df488542fe97ea45e77f77c472824ccec5b30..b6ad80fba4deb565f9ab4fa7224be7315f264ce9 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_runner { +namespace flutter { VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider, sk_sp context, @@ -22,8 +22,6 @@ 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; @@ -55,7 +53,6 @@ VulkanSurface::VulkanSurface(vulkan::VulkanProvider& vulkan_provider, } VulkanSurface::~VulkanSurface() { - ASSERT_IS_GPU_THREAD; if (async_) { wait_.Cancel(async_); wait_.set_object(ZX_HANDLE_INVALID); @@ -325,7 +322,6 @@ bool VulkanSurface::PushSessionImageSetupOps(scenic_lib::Session* session, } scenic_lib::Image* VulkanSurface::GetImage() { - ASSERT_IS_GPU_THREAD; if (!valid_) { return 0; } @@ -333,7 +329,6 @@ scenic_lib::Image* VulkanSurface::GetImage() { } sk_sp VulkanSurface::GetSkiaSurface() const { - ASSERT_IS_GPU_THREAD; return valid_ ? sk_surface_ : nullptr; } @@ -358,7 +353,6 @@ bool VulkanSurface::FlushSessionAcquireAndReleaseEvents() { void VulkanSurface::SignalWritesFinished( std::function on_writes_committed) { - ASSERT_IS_GPU_THREAD; FXL_DCHECK(on_writes_committed); if (!valid_) { @@ -374,8 +368,6 @@ 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; @@ -410,10 +402,10 @@ void VulkanSurface::Reset() { } } -async_wait_result_t VulkanSurface::OnHandleReady(async_t* async, - zx_status_t status, - const zx_packet_signal_t* signal) { - ASSERT_IS_GPU_THREAD; +async_wait_result_t VulkanSurface::OnHandleReady( + async_t* async, + zx_status_t status, + const zx_packet_signal_t* signal) { if (status != ZX_OK) return ASYNC_WAIT_FINISHED; FXL_DCHECK(signal->observed & ZX_EVENT_SIGNALED); @@ -421,4 +413,4 @@ async_wait_result_t VulkanSurface::OnHandleReady(async_t* async, return ASYNC_WAIT_AGAIN; } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface.h b/content_handler/vulkan_surface.h index 41a807af81f9cbbeae77b07e0805088824890035..7add6b05bb8ccbcf3cfec07e8b818ed135be0c10 100644 --- a/content_handler/vulkan_surface.h +++ b/content_handler/vulkan_surface.h @@ -20,9 +20,10 @@ #include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/gpu/vk/GrVkBackendContext.h" -namespace flutter_runner { +namespace flutter { -class VulkanSurface : public flow::SceneUpdateContext::SurfaceProducerSurface { +class VulkanSurface final + : public flow::SceneUpdateContext::SurfaceProducerSurface { public: VulkanSurface(vulkan::VulkanProvider& vulkan_provider, sk_sp context, @@ -32,12 +33,16 @@ class VulkanSurface : public flow::SceneUpdateContext::SurfaceProducerSurface { ~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 @@ -115,4 +120,4 @@ class VulkanSurface : public flow::SceneUpdateContext::SurfaceProducerSurface { FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurface); }; -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface_pool.cc b/content_handler/vulkan_surface_pool.cc index af23ef711b7ad96e13fcd9fee9537e4bbbdc2241..93d14c2ddbff797837cadfeed0040d8081b26c06 100644 --- a/content_handler/vulkan_surface_pool.cc +++ b/content_handler/vulkan_surface_pool.cc @@ -2,13 +2,14 @@ // 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_runner { +namespace flutter { VulkanSurfacePool::VulkanSurfacePool(vulkan::VulkanProvider& vulkan_provider, sk_sp context, @@ -177,4 +178,4 @@ void VulkanSurfacePool::TraceStats() { trace_surfaces_reused_ = 0; } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface_pool.h b/content_handler/vulkan_surface_pool.h index 52dd3ed6aa417bcd75984e047c8763b52ef44517..4900816762910c60d70ac50862a666bb58f43f30 100644 --- a/content_handler/vulkan_surface_pool.h +++ b/content_handler/vulkan_surface_pool.h @@ -6,12 +6,13 @@ #include #include -#include "flutter/content_handler/vulkan_surface.h" + #include "lib/fxl/macros.h" +#include "vulkan_surface.h" -namespace flutter_runner { +namespace flutter { -class VulkanSurfacePool { +class VulkanSurfacePool final { public: static const size_t kMaxSurfacesOfSameSize = 3; static const size_t kMaxSurfaceAge = 3; @@ -74,4 +75,4 @@ class VulkanSurfacePool { FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfacePool); }; -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface_producer.cc b/content_handler/vulkan_surface_producer.cc index 6f605c109b7dfd9861a6685ae8d0f22b2b1ba834..ff8a9ab9d1f4a2a0dc89f24c04b7225a0aa46439 100644 --- a/content_handler/vulkan_surface_producer.cc +++ b/content_handler/vulkan_surface_producer.cc @@ -2,17 +2,18 @@ // 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_surface_producer.h" +#include "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_runner { +namespace flutter { VulkanSurfaceProducer::VulkanSurfaceProducer( scenic_lib::Session* mozart_session) { @@ -42,7 +43,7 @@ bool VulkanSurfaceProducer::Initialize(scenic_lib::Session* mozart_session) { VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, }; application_ = std::make_unique( - *vk_, "FlutterContentHandler", std::move(extensions)); + *vk_, "FlutterApplicationRunner", std::move(extensions)); if (!application_->IsValid() || !vk_->AreInstanceProcsSetup()) { // Make certain the application instance was created and it setup the @@ -200,4 +201,4 @@ void VulkanSurfaceProducer::SubmitSurface( surface_pool_->SubmitSurface(std::move(surface)); } -} // namespace flutter_runner +} // namespace flutter diff --git a/content_handler/vulkan_surface_producer.h b/content_handler/vulkan_surface_producer.h index 2338a8a6ba709e7b5ea0f313967506020d08a231..15c4419e8cde7d1e7bb57ca994f7151b6b892c42 100644 --- a/content_handler/vulkan_surface_producer.h +++ b/content_handler/vulkan_surface_producer.h @@ -2,11 +2,8 @@ // 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_SURFACE_PRODUCER_H_ -#define FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ +#pragma once -#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" @@ -17,11 +14,14 @@ #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_runner { +namespace flutter { -class VulkanSurfaceProducer : public flow::SceneUpdateContext::SurfaceProducer, - public vulkan::VulkanProvider { +class VulkanSurfaceProducer final + : public flow::SceneUpdateContext::SurfaceProducer, + public vulkan::VulkanProvider { public: VulkanSurfaceProducer(scenic_lib::Session* mozart_session); @@ -74,6 +74,4 @@ class VulkanSurfaceProducer : public flow::SceneUpdateContext::SurfaceProducer, FXL_DISALLOW_COPY_AND_ASSIGN(VulkanSurfaceProducer); }; -} // namespace flutter_runner - -#endif // FLUTTER_CONTENT_HANDLER_VULKAN_SURFACE_PRODUCER_H_ +} // namespace flutter diff --git a/flow/BUILD.gn b/flow/BUILD.gn index e6a6411a6c1da2ff2649a0a8e5cdd6fe49e37ddc..07c5d4e5d4e7b8f1d7415ab2db85680cf0850ec2 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -48,11 +48,12 @@ 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", ] @@ -61,12 +62,11 @@ 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", - "//third_party/dart/runtime:libdart_jit", # for tracing "$flutter_root/testing", + "//third_party/dart/runtime:libdart_jit", # for tracing "//third_party/skia", ] } diff --git a/flow/compositor_context.cc b/flow/compositor_context.cc index e0d17229e7981e1b669312b5b969f20af65336c4..53659103be9f19150796875e2e51cb8749fdc99a 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(std::unique_ptr info) - : process_info_(std::move(info)) {} +CompositorContext::CompositorContext() = default; CompositorContext::~CompositorContext() = default; @@ -18,10 +18,6 @@ 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()); - } } } @@ -33,11 +29,12 @@ void CompositorContext::EndFrame(ScopedFrame& frame, } } -CompositorContext::ScopedFrame CompositorContext::AcquireFrame( +std::unique_ptr CompositorContext::AcquireFrame( GrContext* gr_context, SkCanvas* canvas, bool instrumentation_enabled) { - return ScopedFrame(*this, gr_context, canvas, instrumentation_enabled); + return std::make_unique(*this, gr_context, canvas, + instrumentation_enabled); } CompositorContext::ScopedFrame::ScopedFrame(CompositorContext& context, @@ -51,18 +48,23 @@ 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 2d310422747b77e1c47c68ac64330ddd1897670f..14c2449dbecd066cab008912abcd2c7f4de3956a 100644 --- a/flow/compositor_context.h +++ b/flow/compositor_context.h @@ -9,7 +9,6 @@ #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" @@ -18,19 +17,26 @@ 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_; } - ScopedFrame(ScopedFrame&& frame); - - ~ScopedFrame(); + virtual bool Raster(LayerTree& layer_tree, bool ignore_raster_cache); private: CompositorContext& context_; @@ -38,23 +44,17 @@ 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(std::unique_ptr info); + CompositorContext(); - ~CompositorContext(); + virtual ~CompositorContext(); - ScopedFrame AcquireFrame(GrContext* gr_context, - SkCanvas* canvas, - bool instrumentation_enabled = true); + virtual std::unique_ptr AcquireFrame( + GrContext* gr_context, + SkCanvas* canvas, + bool instrumentation_enabled); 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,20 +70,12 @@ 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_; - std::unique_ptr process_info_; + TextureRegistry texture_registry_; 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 0aa5b4b3b7d2dc2f22d8f66ec78a4e9723c40c14..3311b9c2b43e3430a26b99003574606e95af4253 100644 --- a/flow/debug_print.cc +++ b/flow/debug_print.cc @@ -80,3 +80,8 @@ 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 ca5973eeb0977cb45401cb178ce0f0c2003614e8..78a28fe38562ddaa06a90015adfbf537b6fc8caa 100644 --- a/flow/debug_print.h +++ b/flow/debug_print.h @@ -15,14 +15,15 @@ #define DEF_PRINTER(x) std::ostream& operator<<(std::ostream&, const x&); -DEF_PRINTER(flow::RasterCacheKey); DEF_PRINTER(flow::MatrixDecomposition); +DEF_PRINTER(flow::RasterCacheKey); +DEF_PRINTER(SkISize); DEF_PRINTER(SkMatrix); DEF_PRINTER(SkMatrix44); -DEF_PRINTER(SkVector3); -DEF_PRINTER(SkVector4); +DEF_PRINTER(SkPoint); DEF_PRINTER(SkRect); DEF_PRINTER(SkRRect); -DEF_PRINTER(SkPoint); +DEF_PRINTER(SkVector3); +DEF_PRINTER(SkVector4); #endif // FLUTTER_FLOW_DEBUG_PRINT_H_ diff --git a/flow/export_node.cc b/flow/export_node.cc index a130c426a75bfde36dca4270814ab3a39cb5699b..27ab34030ca425e4dbd75c2ad7b992d9b24c66fb 100644 --- a/flow/export_node.cc +++ b/flow/export_node.cc @@ -4,28 +4,27 @@ #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) - : export_node_(std::make_unique(export_token_handle)) { - ASSERT_IS_UI_THREAD; + : gpu_task_runner_(std::move(gpu_task_runner)), + export_node_(std::make_unique(export_token_handle)) { + FXL_DCHECK(gpu_task_runner_); } 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() { - ASSERT_IS_UI_THREAD; - blink::Threads::Gpu()->PostTask( + gpu_task_runner_->PostTask( fxl::MakeCopyable([export_node = std::move(export_node_)]() { export_node->Dispose(true); })); @@ -44,8 +43,6 @@ 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())); @@ -67,8 +64,6 @@ 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 24f94fcebf20fcc3cdffe145681398765987abae..e6a11175e561e7cfc838180197598d8456032338 100644 --- a/flow/export_node.h +++ b/flow/export_node.h @@ -15,6 +15,7 @@ #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 { @@ -24,7 +25,8 @@ namespace flow { // held by the ExportNode. class ExportNodeHolder : public fxl::RefCountedThreadSafe { public: - ExportNodeHolder(fxl::RefPtr export_token_handle); + ExportNodeHolder(fxl::RefPtr gpu_task_runner, + fxl::RefPtr export_token_handle); ~ExportNodeHolder(); // Calls Bind() on the wrapped ExportNode. @@ -36,6 +38,7 @@ 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 a33b0eaa681b7603449ca99ec0358e663d95ba54..ca228a7d58f7609d58712552272488dc96437db3 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, - sk_sp picture, + SkiaGPUObject picture, bool picture_is_complex, bool picture_will_change) { if (!current_layer_) { return; } - SkRect pictureRect = picture->cullRect(); + SkRect pictureRect = picture.get()->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(picture); + layer->set_picture(std::move(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 a62ec46714d21dde39b62dcb2bc4f278d5b8d534..cadd173ab5a84fc46db9feb0440430e608be83b7 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, - sk_sp picture, + SkiaGPUObject picture, bool picture_is_complex, bool picture_will_change) override; diff --git a/flow/layers/layer.h b/flow/layers/layer.h index d0ef1990ab4f20683b841e0790ea53cfde4d0f17..cf7ad71c36fae37e268f7d7e6fc63da5b25d9612 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -44,9 +44,6 @@ 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; @@ -59,7 +56,6 @@ 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 91ae13974a23b7d29845b18590525ccd68d51246..a29e959514428f4dc23bb7417110527f6d3148cb 100644 --- a/flow/layers/layer_builder.h +++ b/flow/layers/layer_builder.h @@ -8,6 +8,7 @@ #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" @@ -57,7 +58,7 @@ class LayerBuilder { const SkRect& rect) = 0; virtual void PushPicture(const SkPoint& offset, - sk_sp picture, + SkiaGPUObject 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 fde2fc4bf08665a1c8aa7304439c39aabfb1a22d..d9fb37419468879dcd0af6fcd2aed9c52919ecd2 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -17,43 +17,18 @@ 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 = { -#if defined(OS_FUCHSIA) - metrics, -#endif - ignore_raster_cache ? nullptr : &frame.context().raster_cache(), - frame.gr_context(), - color_space, - SkRect::MakeEmpty(), + ignore_raster_cache ? nullptr : &frame.context().raster_cache(), + frame.gr_context(), + color_space, + SkRect::MakeEmpty(), }; root_layer_->Preroll(&context, SkMatrix::I()); @@ -63,9 +38,12 @@ void LayerTree::Preroll(CompositorContext::ScopedFrame& frame, void LayerTree::UpdateScene(SceneUpdateContext& context, scenic_lib::ContainerNode& container) { TRACE_EVENT0("flutter", "LayerTree::UpdateScene"); - - SceneUpdateContext::Transform transform(context, 1.f / device_pixel_ratio_, - 1.f / device_pixel_ratio_, 1.f); + 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::Frame frame( context, SkRRect::MakeRect( @@ -82,12 +60,13 @@ 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().memory_usage(), - frame.context().texture_registry(), - checkerboard_offscreen_layers_}; + Layer::PaintContext context = { + *frame.canvas(), // + frame.context().frame_time(), // + frame.context().engine_time(), // + 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 5ddebd088de9e5e7d4d63d0cbcf0b6e0883b1d1d..25a8e072cfa2154351440d2c0fb2116cb1f9fd38 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -13,9 +13,6 @@ #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 { @@ -26,24 +23,10 @@ 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 @@ -93,10 +76,6 @@ 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 cc55500115a0855acce44172206b2c8256475ade..7d871af33b94f339fb70d5505fb384403cd042ad 100644 --- a/flow/layers/performance_overlay_layer.cc +++ b/flow/layers/performance_overlay_layer.cc @@ -57,34 +57,6 @@ 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) @@ -111,11 +83,6 @@ 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 e7c3ac530a02a5b0cfae8ddc56cbe3a0857d2fd8..77448107147a49ab71461ed7f5984b4a555580e7 100644 --- a/flow/layers/performance_overlay_layer.h +++ b/flow/layers/performance_overlay_layer.h @@ -14,8 +14,6 @@ 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 4a99d7d07f75e82a9ba54699efc94251196cbd10..552ca0443bd804121e0954cade60175a30122773 100644 --- a/flow/layers/picture_layer.cc +++ b/flow/layers/picture_layer.cc @@ -4,39 +4,30 @@ #include "flutter/flow/layers/picture_layer.h" -#include "flutter/common/threads.h" #include "lib/fxl/logging.h" namespace flow { 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(); }); - } -} +PictureLayer::~PictureLayer() = default; 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, picture_.get(), matrix, context->dst_color_space, -#if defined(OS_FUCHSIA) - context->metrics, -#endif + context->gr_context, sk_picture, matrix, context->dst_color_space, is_complex_, will_change_); } - SkRect bounds = picture_->cullRect().makeOffset(offset_.x(), offset_.y()); + SkRect bounds = sk_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_); + FXL_DCHECK(picture_.get()); FXL_DCHECK(needs_painting()); SkAutoCanvasRestore save(&context.canvas, true); @@ -53,7 +44,7 @@ void PictureLayer::Paint(PaintContext& context) const { SkCanvas::kStrict_SrcRectConstraint // source constraint ); } else { - context.canvas.drawPicture(picture_.get()); + context.canvas.drawPicture(picture()); } } diff --git a/flow/layers/picture_layer.h b/flow/layers/picture_layer.h index 191ef9d7097a2c51ac9141a55207b253c7edb481..c67929b7cb45502ae912460b177bff66d6d967d2 100644 --- a/flow/layers/picture_layer.h +++ b/flow/layers/picture_layer.h @@ -5,8 +5,11 @@ #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 { @@ -16,12 +19,14 @@ class PictureLayer : public Layer { ~PictureLayer() override; void set_offset(const SkPoint& offset) { offset_ = offset; } - void set_picture(sk_sp picture) { picture_ = std::move(picture); } + void set_picture(SkiaGPUObject 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(); } + SkPicture* picture() const { return picture_.get().get(); } void Preroll(PrerollContext* frame, const SkMatrix& matrix) override; @@ -29,7 +34,9 @@ class PictureLayer : public Layer { private: SkPoint offset_; - sk_sp picture_; + // Even though pictures themselves are not GPU resources, they may reference + // images that have a reference to a GPU resource. + SkiaGPUObject 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 deleted file mode 100644 index 6623fe72573962cbb742bd6d2b80c02c9b48ba50..0000000000000000000000000000000000000000 --- a/flow/process_info.h +++ /dev/null @@ -1,31 +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. - -#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 aa9fad0e281de0429e0cc7963b9077ef6aad101a..11a86729b489b7c31c36ffaea8533511586d6df3 100644 --- a/flow/raster_cache.cc +++ b/flow/raster_cache.cc @@ -6,7 +6,6 @@ #include -#include "flutter/common/threads.h" #include "flutter/flow/paint_utils.h" #include "flutter/glue/trace_event.h" #include "lib/fxl/logging.h" @@ -73,9 +72,6 @@ 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"); @@ -83,17 +79,9 @@ RasterCacheResult RasterizePicture(SkPicture* picture, const SkRect logical_rect = picture->cullRect(); -#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 SkRect physical_rect = + SkRect::MakeWH(std::fabs(logical_rect.width() * scale.x()), + std::fabs(logical_rect.height() * scale.y())); const SkImageInfo image_info = SkImageInfo::MakeN32Premul( std::ceil(physical_rect.width()), // physical width @@ -120,8 +108,7 @@ RasterCacheResult RasterizePicture(SkPicture* picture, } canvas->clear(SK_ColorTRANSPARENT); - canvas->scale(std::abs(scale.x() * metrics_scale_x), - std::abs(scale.y() * metrics_scale_y)); + canvas->scale(std::abs(scale.x()), std::abs(scale.y())); canvas->translate(-logical_rect.left(), -logical_rect.top()); canvas->drawPicture(picture); @@ -153,9 +140,6 @@ 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)) { @@ -172,11 +156,7 @@ RasterCacheResult RasterCache::GetPrerolledImage( return {}; } - RasterCacheKey cache_key(*picture, -#if defined(OS_FUCHSIA) - metrics->scale_x, metrics->scale_y, -#endif - matrix); + RasterCacheKey cache_key(*picture, matrix); Entry& entry = cache_[cache_key]; entry.access_count = ClampSize(entry.access_count + 1, 0, threshold_); @@ -189,9 +169,6 @@ 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 31201049b61191b65e50c07a56a812cfed6cf324..3278eb355b030149569df3da72252ca760c46d42 100644 --- a/flow/raster_cache.h +++ b/flow/raster_cache.h @@ -12,9 +12,6 @@ #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" @@ -57,9 +54,6 @@ 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 83df52658c981afa6f9bdab7c82ec2c98afb502d..1f28ea5320d361e87f501153d833352ceed5e51e 100644 --- a/flow/raster_cache_key.h +++ b/flow/raster_cache_key.h @@ -15,30 +15,15 @@ namespace flow { class RasterCacheKey { public: - RasterCacheKey(const SkPicture& picture, -#if defined(OS_FUCHSIA) - float metrics_scale_x, - float metrics_scale_y, -#endif - const MatrixDecomposition& matrix) + RasterCacheKey(const SkPicture& picture, const MatrixDecomposition& matrix) : picture_id_(picture.uniqueID()), -#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)) { - } + 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_; @@ -49,11 +34,6 @@ 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_; } }; @@ -63,10 +43,6 @@ 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 83883c508b4df4d301b05551cca379551c10465c..b9d6801cc82ee9241e8d5f31430ab11d83351219 100644 --- a/flow/scene_update_context.cc +++ b/flow/scene_update_context.cc @@ -4,7 +4,6 @@ #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" @@ -19,9 +18,7 @@ SceneUpdateContext::SceneUpdateContext(scenic_lib::Session* session, } SceneUpdateContext::~SceneUpdateContext() { - ASSERT_IS_GPU_THREAD; - - // Release Scenic session resources for all ExportNodes. + // Release Mozart session resources for all ExportNodes. for (auto export_node : export_nodes_) { export_node->Dispose(false); } @@ -30,21 +27,16 @@ 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); } @@ -195,12 +187,9 @@ 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().memory_usage(), - frame.context().texture_registry(), - false}; + 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 new file mode 100644 index 0000000000000000000000000000000000000000..ce2312f921580e96255db5a3e713eb780b808f40 --- /dev/null +++ b/flow/skia_gpu_object.cc @@ -0,0 +1,44 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..4711f80c6f4fdd51674fedb05d8fb1b06aecf348 --- /dev/null +++ b/flow/skia_gpu_object.h @@ -0,0 +1,88 @@ +// 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 33a48af989477ebb8d699e8c3ab209b9b3d263d9..d5cc3ae228aa7bfb14fce103bfbcbdf46e488321 100644 --- a/flow/texture.cc +++ b/flow/texture.cc @@ -11,36 +11,32 @@ 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 a602a6b45b5b4af7dfb92280282d65ba6da69226..f5e443083408487c547a40d231959fcbe6f40bca 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,6 +29,9 @@ 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 6dabcb446c912e0adfeef127825371484c6234ee..ffbf949cc0957f7e46fad92953616b07d610f585 100644 --- a/fml/BUILD.gn +++ b/fml/BUILD.gn @@ -4,9 +4,12 @@ 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", @@ -14,8 +17,9 @@ 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", @@ -23,6 +27,9 @@ source_set("fml") { "thread_local.h", "trace_event.cc", "trace_event.h", + "unique_fd.cc", + "unique_fd.h", + "unique_object.h", ] deps = [ @@ -95,16 +102,25 @@ 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 new file mode 100644 index 0000000000000000000000000000000000000000..2327b2eef831ee1fdb97caf6c42cb2b29918f9fc --- /dev/null +++ b/fml/file.h @@ -0,0 +1,35 @@ +// 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 093dc3d02b1bc46fbce7b61ce644271c512a211a..0c0acd06dbbdf57f73a80099aeaa7d16fb37606a 100644 --- a/fml/icu_util.cc +++ b/fml/icu_util.cc @@ -22,8 +22,6 @@ 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) { @@ -34,15 +32,15 @@ class ICUContext { bool SetupMapping(const std::string& icu_data_path) { // Check if the explicit path specified exists. - auto overriden_path_mapping = std::make_unique(icu_data_path); - if (overriden_path_mapping->GetSize() != 0) { - mapping_ = std::move(overriden_path_mapping); + auto path_mapping = std::make_unique(icu_data_path, false); + if (path_mapping->GetSize() != 0) { + mapping_ = std::move(path_mapping); return true; } // Check to see if the mapping is in the resources bundle. if (PlatformHasResourcesBundle()) { - auto resource = GetResourceMapping(kIcuDataFileName); + auto resource = GetResourceMapping(icu_data_path); if (resource != nullptr && resource->GetSize() != 0) { mapping_ = std::move(resource); return true; @@ -57,10 +55,8 @@ 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 + kIcuDataFileName); + directory.second + kPathSeparator + icu_data_path, false); if (file->GetSize() != 0) { mapping_ = std::move(file); return true; @@ -96,7 +92,8 @@ 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"; + FXL_CHECK(context->IsValid()) + << "Must be able to initialize the ICU context. Tried: " << icu_data_path; } std::once_flag g_icu_init_flag; diff --git a/fml/macros.h b/fml/macros.h new file mode 100644 index 0000000000000000000000000000000000000000..ba46b9dda4b4dcdfca3450c8df11a309c88ce315 --- /dev/null +++ b/fml/macros.h @@ -0,0 +1,20 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..97d7905015f611b83e6c2f441a068fca599209b7 --- /dev/null +++ b/fml/mapping.cc @@ -0,0 +1,20 @@ +// 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 8963b22a9c1f65e9f69a07dbe49eae048c95d183..00e9685dd6b0c83f436af4f7282dca22eb860588 100644 --- a/fml/mapping.h +++ b/fml/mapping.h @@ -7,14 +7,10 @@ #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 { @@ -39,12 +35,9 @@ std::unique_ptr GetResourceMapping(const std::string& resource_name); class FileMapping : public Mapping { public: - FileMapping(const std::string& path); + FileMapping(const std::string& path, bool executable = false); -// fxl::UniqueFD isn't supported for Windows handles. -#if !OS_WIN - FileMapping(const fxl::UniqueFD& fd); -#endif + FileMapping(const fml::UniqueFD& fd, bool executable = false); ~FileMapping() override; @@ -53,16 +46,32 @@ class FileMapping : public Mapping { const uint8_t* GetMapping() const override; private: - size_t size_; - uint8_t* mapping_; + size_t size_ = 0; + uint8_t* mapping_ = nullptr; #if OS_WIN - HANDLE mapping_handle_; + fml::UniqueFD 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 new file mode 100644 index 0000000000000000000000000000000000000000..f22e9d1cfaf067a50608b78b12bd50e64158b404 --- /dev/null +++ b/fml/memory/thread_checker.h @@ -0,0 +1,69 @@ +// 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 5b85c531966b20bb02adc99acea1d5e54e521788..2b369952d7306a389e8edf5f5c2bd926396a75c4 100644 --- a/fml/memory/weak_ptr.h +++ b/fml/memory/weak_ptr.h @@ -10,12 +10,17 @@ #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; @@ -41,13 +46,17 @@ class WeakPtr { WeakPtr(const WeakPtr& r) = default; template - WeakPtr(const WeakPtr& r) : ptr_(r.ptr_), flag_(r.flag_) {} + WeakPtr(const WeakPtr& r) + : ptr_(static_cast(r.ptr_)), flag_(r.flag_), checker_(r.checker_) {} // Move constructor. WeakPtr(WeakPtr&& r) = default; template - WeakPtr(WeakPtr&& r) : ptr_(r.ptr_), flag_(std::move(r.flag_)) {} + WeakPtr(WeakPtr&& r) + : ptr_(static_cast(r.ptr_)), + flag_(std::move(r.flag_)), + checker_(r.checker_) {} ~WeakPtr() = default; @@ -65,16 +74,24 @@ class WeakPtr { // The following methods should only be called on the same thread as the // "originating" |WeakPtrFactory|. - explicit operator bool() const { return flag_ && flag_->is_valid(); } + explicit operator bool() const { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); + return flag_ && flag_->is_valid(); + } - T* get() const { return *this ? ptr_ : nullptr; } + T* get() const { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); + 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(); } @@ -85,11 +102,14 @@ class WeakPtr { friend class WeakPtrFactory; - explicit WeakPtr(T* ptr, fxl::RefPtr&& flag) - : ptr_(ptr), flag_(std::move(flag)) {} + explicit WeakPtr(T* ptr, + fxl::RefPtr&& flag, + DebugThreadChecker checker) + : ptr_(ptr), flag_(std::move(flag)), checker_(checker) {} T* ptr_; fxl::RefPtr flag_; + DebugThreadChecker checker_; // Copy/move construction/assignment supported. }; @@ -140,19 +160,22 @@ 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()); + return WeakPtr(ptr_, flag_.Clone(), checker_); } // 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(); @@ -162,13 +185,17 @@ 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 { return flag_ && !flag_->HasOneRef(); } + bool HasWeakPtrs() const { + FML_DCHECK_CREATION_THREAD_IS_CURRENT(checker_.checker); + 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 4765cfa76558f8693ebbb9d44b3cb389ba3938c0..44a0e307c1dd14461fabe15d1b9ea5477c3f3b80 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(TaskObserver* observer) { - loop_->AddTaskObserver(observer); +void MessageLoop::AddTaskObserver(intptr_t key, fxl::Closure callback) { + loop_->AddTaskObserver(key, callback); } -void MessageLoop::RemoveTaskObserver(TaskObserver* observer) { - loop_->RemoveTaskObserver(observer); +void MessageLoop::RemoveTaskObserver(intptr_t key) { + loop_->RemoveTaskObserver(key); } void MessageLoop::RunExpiredTasksNow() { diff --git a/fml/message_loop.h b/fml/message_loop.h index 87773619ccc518658030adea0dee8a1da4f6feb6..3bfb1c40c6df72fbc974acdc2688d01431470169 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/task_observer.h" +#include "flutter/fml/macros.h" #include "lib/fxl/macros.h" #include "lib/fxl/tasks/task_runner.h" @@ -16,6 +16,7 @@ class MessageLoopImpl; class MessageLoop { public: + FML_EMBEDDER_ONLY static MessageLoop& GetCurrent(); bool IsValid() const; @@ -24,11 +25,11 @@ class MessageLoop { void Terminate(); - void AddTaskObserver(TaskObserver* observer); + void AddTaskObserver(intptr_t key, fxl::Closure callback); - void RemoveTaskObserver(TaskObserver* observer); + void RemoveTaskObserver(intptr_t key); - 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 cec9b7e448f1a8040af1a63e65e8737bcdb32573..df885f3792d5f45c5686f7678a2ccd492250f45c 100644 --- a/fml/message_loop_impl.cc +++ b/fml/message_loop_impl.cc @@ -2,6 +2,8 @@ // 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 @@ -11,35 +13,29 @@ #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() { - return fxl::MakeRefCounted<::PlatformMessageLoopImpl>(); +#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 } MessageLoopImpl::MessageLoopImpl() : order_(0), terminated_(false) {} @@ -55,20 +51,19 @@ void MessageLoopImpl::RunExpiredTasksNow() { RunExpiredTasks(); } -void MessageLoopImpl::AddTaskObserver(TaskObserver* observer) { - FXL_DCHECK(observer != nullptr); +void MessageLoopImpl::AddTaskObserver(intptr_t key, fxl::Closure callback) { + FXL_DCHECK(callback != nullptr); FXL_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this) << "Message loop task observer must be added on the same thread as the " "loop."; - task_observers_.insert(observer); + task_observers_[key] = std::move(callback); } -void MessageLoopImpl::RemoveTaskObserver(TaskObserver* observer) { - FXL_DCHECK(observer != nullptr); +void MessageLoopImpl::RemoveTaskObserver(intptr_t key) { FXL_DCHECK(MessageLoop::GetCurrent().GetLoopImpl().get() == this) << "Message loop task observer must be removed from the same thread as " "the loop."; - task_observers_.erase(observer); + task_observers_.erase(key); } void MessageLoopImpl::DoRun() { @@ -144,7 +139,7 @@ void MessageLoopImpl::RunExpiredTasks() { for (const auto& invocation : invocations) { invocation(); for (const auto& observer : task_observers_) { - observer->DidProcessTask(); + observer.second(); } } } diff --git a/fml/message_loop_impl.h b/fml/message_loop_impl.h index bfdb2064cb26405711eae1265f76ca27b4fb2050..478cbd1f1a0be06bb83c2cf07a2cc90d91fb6812 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(TaskObserver* observer); + void AddTaskObserver(intptr_t key, fxl::Closure callback); - void RemoveTaskObserver(TaskObserver* observer); + void RemoveTaskObserver(intptr_t key); void DoRun(); @@ -71,7 +71,7 @@ class MessageLoopImpl : public fxl::RefCountedThreadSafe { using DelayedTaskQueue = std:: priority_queue, DelayedTaskCompare>; - std::set task_observers_; + std::map 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 11ea72c3900eb5f4c52db34dc17c080288a423c2..cd2acd308b46a370381d9ab724b756c5e6be6103 100644 --- a/fml/message_loop_unittests.cc +++ b/fml/message_loop_unittests.cc @@ -2,9 +2,12 @@ // 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" @@ -244,22 +247,6 @@ 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; @@ -269,8 +256,7 @@ TEST(MessageLoop, TaskObserverFire) { auto& loop = fml::MessageLoop::GetCurrent(); size_t task_count = 0; size_t obs_count = 0; - CustomTaskObserver obs( - PLATFORM_SPECIFIC_CAPTURE(&obs_count)() { obs_count++; }); + auto 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)() { @@ -282,7 +268,7 @@ TEST(MessageLoop, TaskObserverFire) { } }); } - loop.AddTaskObserver(&obs); + loop.AddTaskObserver(0, 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 new file mode 100644 index 0000000000000000000000000000000000000000..7e48ed6d3a3ffb396ef041dcb734b85427936e1b --- /dev/null +++ b/fml/native_library.h @@ -0,0 +1,52 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..9b06b6847f415c5ef9a4b6e35e99964182f10da7 --- /dev/null +++ b/fml/paths.cc @@ -0,0 +1,31 @@ +// 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 8ec3b4b58047636b8d3d1c11e6b9cf3399302ac3..0d4367654de4a63ca44745c31944b9bba917cb8f 100644 --- a/fml/paths.h +++ b/fml/paths.h @@ -8,11 +8,15 @@ #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 e6d04e82534015382c3985fa91eb4d85ba160b02..19c1eafe798450fdbb4f9ad22919830032c0f522 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 "lib/fxl/files/unique_fd.h" +#include "flutter/fml/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: - fxl::UniqueObject looper_; - fxl::UniqueFD timer_fd_; + fml::UniqueObject looper_; + fml::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 5d1b9664e20bceae3a5097b92099c526a708e35a..3ee100121ad0fdf5c18d5089a0afd4afc4f924bf 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]) { -} + : actual_([[[NSBundle mainBundle] pathForResource:@(resource.c_str()) ofType:nil] UTF8String], + false) {} ResourceMappingDarwin::~ResourceMappingDarwin() = default; diff --git a/fml/platform/fuchsia/paths_fuchsia.cc b/fml/platform/fuchsia/paths_fuchsia.cc new file mode 100644 index 0000000000000000000000000000000000000000..20def9f34fae9d065cbc7e6edf68da6d12d3c03f --- /dev/null +++ b/fml/platform/fuchsia/paths_fuchsia.cc @@ -0,0 +1,15 @@ +// 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 51dc690ce887ba7f58f32ba9c7bfa6e58e802c65..ba5e902d4ac89916c3929edde058e15003534b15 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 "lib/fxl/files/unique_fd.h" +#include "flutter/fml/unique_fd.h" #include "lib/fxl/macros.h" namespace fml { class MessageLoopLinux : public MessageLoopImpl { private: - fxl::UniqueFD epoll_fd_; - fxl::UniqueFD timer_fd_; + fml::UniqueFD epoll_fd_; + fml::UniqueFD timer_fd_; bool running_; MessageLoopLinux(); diff --git a/fml/platform/posix/file_posix.cc b/fml/platform/posix/file_posix.cc new file mode 100644 index 0000000000000000000000000000000000000000..028f49f4d183deee5cb88b4f99e55661cde11a2f --- /dev/null +++ b/fml/platform/posix/file_posix.cc @@ -0,0 +1,71 @@ +// 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 07f7edb074ab9f6eaa206bfde049902b2f7181c6..fc53d6a4f7fc939dfcf6257dd921334555911e43 100644 --- a/fml/platform/posix/mapping_posix.cc +++ b/fml/platform/posix/mapping_posix.cc @@ -11,6 +11,7 @@ #include +#include "flutter/fml/unique_fd.h" #include "lib/fxl/build_config.h" #include "lib/fxl/files/eintr_wrapper.h" @@ -39,11 +40,11 @@ std::unique_ptr GetResourceMapping(const std::string& resource_name) { return std::make_unique(resource_name); } -FileMapping::FileMapping(const std::string& path) - : FileMapping(fxl::UniqueFD{HANDLE_EINTR(::open(path.c_str(), O_RDONLY))}) { -} +FileMapping::FileMapping(const std::string& path, bool executable) + : FileMapping(fml::UniqueFD{HANDLE_EINTR(::open(path.c_str(), O_RDONLY))}, + executable) {} -FileMapping::FileMapping(const fxl::UniqueFD& handle) +FileMapping::FileMapping(const fml::UniqueFD& handle, bool executable) : size_(0), mapping_(nullptr) { if (!handle.is_valid()) { return; @@ -59,8 +60,13 @@ FileMapping::FileMapping(const fxl::UniqueFD& handle) return; } - auto mapping = ::mmap(nullptr, stat_buffer.st_size, PROT_READ, MAP_PRIVATE, - handle.get(), 0); + int flags = PROT_READ; + if (executable) { + flags |= PROT_EXEC; + } + + auto mapping = + ::mmap(nullptr, stat_buffer.st_size, flags, 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 new file mode 100644 index 0000000000000000000000000000000000000000..1255c38fc082153036eb1f4a9d206f9ba4e555bd --- /dev/null +++ b/fml/platform/posix/native_library_posix.cc @@ -0,0 +1,60 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..3f5e90494b013908cdd40bf3a09e9a0537631889 --- /dev/null +++ b/fml/platform/win/file_win.cc @@ -0,0 +1,119 @@ +// 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 fd404a14f37dc6287462046be3d0d42b4dcbb7d6..9dd5dcf6f22498d9bf9758817888b0cfd26b549b 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 "lib/fxl/build_config.h" - -#include -#include +#include "flutter/fml/file.h" +#include "flutter/fml/platform/win/wstring_conversion.h" using PlatformResourceMapping = fml::FileMapping; @@ -29,47 +29,50 @@ std::unique_ptr GetResourceMapping(const std::string& resource_name) { return std::make_unique(resource_name); } -FileMapping::FileMapping(const std::string& path) - : size_(0), mapping_(nullptr) { - 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); +FileMapping::FileMapping(const std::string& path, bool executable) + : FileMapping(OpenFile(path.c_str(), + executable ? OpenPermission::kExecute + : OpenPermission::kRead, + false), + executable) {} - if (file_handle_ == INVALID_HANDLE_VALUE) { +FileMapping::FileMapping(const fml::UniqueFD& fd, bool executable) + : size_(0), mapping_(nullptr) { + if (!fd.is_valid()) { return; } - size_ = GetFileSize(file_handle_, nullptr); - if (size_ == INVALID_FILE_SIZE) { - size_ = 0; - return; + if (auto size = ::GetFileSize(fd.get(), nullptr)) { + if (size > 0) { + size_ = size; + } else { + return; + } } - mapping_handle_ = CreateFileMapping(file_handle_, nullptr, PAGE_READONLY, 0, - size_, nullptr); + const DWORD protect = executable ? PAGE_EXECUTE_READ : PAGE_READONLY; - CloseHandle(file_handle_); + mapping_handle_.reset(::CreateFileMapping(fd.get(), // hFile + nullptr, // lpAttributes + protect, // flProtect + 0, // dwMaximumSizeHigh + 0, // dwMaximumSizeLow + nullptr // lpName + )); - if (mapping_handle_ == INVALID_HANDLE_VALUE) { + if (!mapping_handle_.is_valid()) { return; } - 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; - } + const DWORD desired_access = executable ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ; - mapping_ = static_cast(mapping); + mapping_ = reinterpret_cast( + MapViewOfFile(mapping_handle_.get(), desired_access, 0, 0, size_)); } 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 new file mode 100644 index 0000000000000000000000000000000000000000..6992f06f3e8862208105e10897a7eed34bf43a29 --- /dev/null +++ b/fml/platform/win/native_library_win.cc @@ -0,0 +1,51 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..0682dd84067bfc761629a61fa4619781451ada15 --- /dev/null +++ b/fml/platform/win/wstring_conversion.h @@ -0,0 +1,25 @@ +// 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 deleted file mode 100644 index 21697cf022005008006922c65f8cc6c0c3294892..0000000000000000000000000000000000000000 --- a/fml/task_observer.h +++ /dev/null @@ -1,21 +0,0 @@ -// 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 3d13674d78c11a3d0361fee7fc6b1a872b601699..95f91de8e9124668542322b7e0a56e70c05b70d2 100644 --- a/fml/task_runner.cc +++ b/fml/task_runner.cc @@ -2,6 +2,8 @@ // 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 @@ -38,4 +40,14 @@ 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 20ea85e4e521bab3f708f77d724f28f6d311e7bc..3b3d2de01639ded54a95ffe5588883394af3566d 100644 --- a/fml/task_runner.h +++ b/fml/task_runner.h @@ -13,7 +13,7 @@ namespace fml { class MessageLoopImpl; -class TaskRunner : public fxl::TaskRunner { +class TaskRunner final : public fxl::TaskRunner { public: void PostTask(fxl::Closure task) override; @@ -23,12 +23,15 @@ class TaskRunner : public fxl::TaskRunner { bool RunsTasksOnCurrentThread() override; + static void RunNowOrPostTask(fxl::RefPtr runner, + fxl::Closure task); + private: fxl::RefPtr loop_; TaskRunner(fxl::RefPtr loop); - ~TaskRunner(); + ~TaskRunner() override; FRIEND_MAKE_REF_COUNTED(TaskRunner); FRIEND_REF_COUNTED_THREAD_SAFE(TaskRunner); diff --git a/fml/thread.cc b/fml/thread.cc index a1500bfef46a437f8680cff654d486dd7e2c7b25..de4ee6dd368a8f347d3164d169fd11b95aeabdb8 100644 --- a/fml/thread.cc +++ b/fml/thread.cc @@ -2,6 +2,8 @@ // 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" @@ -22,7 +24,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(); @@ -39,7 +41,7 @@ Thread::~Thread() { Join(); } -fxl::RefPtr Thread::GetTaskRunner() const { +fxl::RefPtr Thread::GetTaskRunner() const { return task_runner_; } @@ -84,7 +86,8 @@ void Thread::SetCurrentThreadName(const std::string& name) { } __except (EXCEPTION_CONTINUE_EXECUTION) { } #else -#error Unsupported Platform + FXL_DLOG(INFO) << "Could not set the thread name to '" << name + << "' on this platform."; #endif } diff --git a/fml/thread.h b/fml/thread.h index 44062f10321166206ff1927e86de297dae4c962d..542871f78884535c8ed0d66a8f4e717b8c8f6d7e 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 new file mode 100644 index 0000000000000000000000000000000000000000..bab79f7a9b7436a4f4214c1eb90d341f17d285bd --- /dev/null +++ b/fml/unique_fd.cc @@ -0,0 +1,35 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..9f2d796579d8c04e5990f946972794a1d4be7658 --- /dev/null +++ b/fml/unique_fd.h @@ -0,0 +1,60 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..e2487a53881a9ea20b903b0fcf5bdf131fc244cf --- /dev/null +++ b/fml/unique_object.h @@ -0,0 +1,137 @@ +// 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 2b53ffc4d4f6d971e65a7041909f25d8b1663ad5..8c568f4773c9029773aabddd7e9f0456c0534f76 100644 --- a/lib/snapshot/BUILD.gn +++ b/lib/snapshot/BUILD.gn @@ -29,20 +29,40 @@ if (is_fuchsia) { # The sole purpose of this target is to generate a .packages file. sources = [] - infer_package_name = true + dot_packages_file = "$target_gen_dir/snapshot.packages" + outputs = [ + dot_packages_file, + ] + deps = [] + foreach(dep, dart_deps) { + deps += [ "$dep($dart_toolchain)" ] + } disable_analysis = true - deps = [ - "//topaz/public/dart/fuchsia", - "//topaz/public/dart/zircon", - ] + 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 } } 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). @@ -85,9 +105,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 = [ @@ -209,7 +229,7 @@ bin_to_assembly("isolate_snapshot_data_assembly") { ] input = "$target_gen_dir/isolate_snapshot.bin" output = "$target_gen_dir/isolate_snapshot_data.S" - symbol = "kDartIsolateCoreSnapshotData" + symbol = "kDartIsolateSnapshotData" executable = false } @@ -219,7 +239,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 = "kDartIsolateCoreSnapshotInstructions" + symbol = "kDartIsolateSnapshotInstructions" executable = true } @@ -249,9 +269,9 @@ compile_platform("non_strong_platform") { ] args = [ - "--target=flutter", - "dart:core", - ] + "--target=flutter", + "dart:core", + ] } compile_platform("strong_platform") { @@ -265,10 +285,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 8b3be72d5973b0b7002a4697f71e287b0f48c899..6a75cd22c8614f4ef8226171db27eabd5aca9776 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -40,14 +40,10 @@ 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", @@ -87,19 +83,18 @@ 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 006826abbfdf68cd1a0c4c99cb273966950444ff..60b911cb4ddec2579a48b6e73d210bba49e05d08 100644 --- a/lib/ui/compositing/scene_builder.cc +++ b/lib/ui/compositing/scene_builder.cc @@ -120,10 +120,11 @@ void SceneBuilder::addPicture(double dx, double dy, Picture* picture, int hints) { - layer_builder_->PushPicture(SkPoint::Make(dx, dy), // - picture->picture(), // - !!(hints & 1), // picture is complex - !!(hints & 2) // picture will change + layer_builder_->PushPicture( + SkPoint::Make(dx, dy), // + UIDartState::CreateGPUObject(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 c0e4c5332580a4967c291b5d62863617aa7f102d..f5e0cfb3547d8c576d302d7fccb770d1ed3d0c02 100644 --- a/lib/ui/compositing/scene_host.cc +++ b/lib/ui/compositing/scene_host.cc @@ -4,6 +4,7 @@ #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" @@ -37,8 +38,9 @@ fxl::RefPtr SceneHost::create( } SceneHost::SceneHost(fxl::RefPtr export_token_handle) { - export_node_holder_ = - fxl::MakeRefCounted(export_token_handle); + export_node_holder_ = fxl::MakeRefCounted( + blink::UIDartState::Current()->GetTaskRunners().GetGPUTaskRunner(), + 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 edd51245b05db72c39a7ef8e034bd654c65f9579..32a244c9cb67d6cdc3f98c6c52ac672155821d3c 100644 --- a/lib/ui/dart_runtime_hooks.cc +++ b/lib/ui/dart_runtime_hooks.cc @@ -8,7 +8,11 @@ #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" @@ -141,17 +145,43 @@ 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) { - 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 { + 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 + { #if defined(OS_ANDROID) // Write to the logcat on Android. - const char* tag = Settings::Get().log_tag.c_str(); - __android_log_print(ANDROID_LOG_INFO, tag, "%.*s", (int)length, chars); + __android_log_print(ANDROID_LOG_INFO, logger_prefix.c_str(), "%.*s", + (int)length, chars); #elif defined(OS_IOS) // Write to syslog on iOS. // @@ -159,26 +189,22 @@ void Logger_PrintString(Dart_NativeArguments args) { // iOS logging APIs altogether. syslog(1 /* LOG_ALERT */, "%.*s", (int)length, chars); #else - // 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); + std::cout << log_string << std::endl; #endif } + if (dart::bin::ShouldCaptureStdout()) { // For now we report print output on the Stdout stream. uint8_t newline[] = {'\n'}; - Dart_ServiceSendDataEvent("Stdout", "WriteEvent", chars, length); + Dart_ServiceSendDataEvent("Stdout", "WriteEvent", + reinterpret_cast(chars), length); Dart_ServiceSendDataEvent("Stdout", "WriteEvent", newline, sizeof(newline)); } } void ScheduleMicrotask(Dart_NativeArguments args) { Dart_Handle closure = Dart_GetNativeArgument(args, 0); - if (LogIfError(closure) || !Dart_IsClosure(closure)) - return; - tonic::DartMicrotaskQueue::GetForCurrentThread()->ScheduleMicrotask(closure); + UIDartState::Current()->ScheduleMicrotask(closure); } } // namespace blink diff --git a/lib/ui/painting/codec.cc b/lib/ui/painting/codec.cc index 3e47ba86d50a5f8961f09492532db403b2a73838..758a722b409e22d12db4e741abf3d7e22202fe5f 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/threads.h" +#include "flutter/common/task_runners.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,6 +17,10 @@ #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; @@ -28,9 +32,9 @@ namespace { static constexpr const char* kInitCodecTraceTag = "InitCodec"; static constexpr const char* kCodecNextFrameTraceTag = "CodecNextFrame"; -void InvokeCodecCallback(fxl::RefPtr codec, - std::unique_ptr callback, - size_t trace_id) { +static 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); @@ -45,7 +49,9 @@ void InvokeCodecCallback(fxl::RefPtr codec, TRACE_FLOW_END("flutter", kInitCodecTraceTag, trace_id); } -sk_sp DecodeImage(sk_sp buffer, size_t trace_id) { +static sk_sp DecodeImage(fml::WeakPtr context, + sk_sp buffer, + size_t trace_id) { TRACE_FLOW_STEP("flutter", kInitCodecTraceTag, trace_id); TRACE_EVENT0("flutter", "DecodeImage"); @@ -53,13 +59,11 @@ sk_sp DecodeImage(sk_sp buffer, size_t trace_id) { 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, std::move(buffer), - false, dstColorSpace.get()); + return SkImage::MakeCrossContextFromEncoded( + context.get(), 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 @@ -68,7 +72,10 @@ sk_sp DecodeImage(sk_sp buffer, size_t trace_id) { } } -fxl::RefPtr InitCodec(sk_sp buffer, size_t trace_id) { +fxl::RefPtr InitCodec(fml::WeakPtr context, + sk_sp buffer, + fxl::RefPtr unref_queue, + size_t trace_id) { TRACE_FLOW_STEP("flutter", kInitCodecTraceTag, trace_id); TRACE_EVENT0("blink", "InitCodec"); @@ -86,27 +93,31 @@ fxl::RefPtr InitCodec(sk_sp buffer, size_t trace_id) { if (skCodec->getFrameCount() > 1) { return fxl::MakeRefCounted(std::move(skCodec)); } - auto skImage = DecodeImage(buffer, trace_id); + auto skImage = DecodeImage(context, buffer, trace_id); if (!skImage) { FXL_LOG(ERROR) << "DecodeImage failed"; return nullptr; } auto image = CanvasImage::Create(); - image->set_image(skImage); + image->set_image({skImage, unref_queue}); 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(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); - })); + 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); + })); } void InstantiateImageCodec(Dart_NativeArguments args) { @@ -133,14 +144,20 @@ void InstantiateImageCodec(Dart_NativeArguments args) { auto buffer = SkData::MakeWithCopy(list.data(), list.num_elements()); - 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); - })); + 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); + })); } bool copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) { @@ -213,7 +230,8 @@ MultiFrameCodec::MultiFrameCodec(std::unique_ptr codec) nextFrameIndex_ = 0; } -sk_sp MultiFrameCodec::GetNextFrameImage() { +sk_sp MultiFrameCodec::GetNextFrameImage( + fml::WeakPtr resourceContext) { SkBitmap& bitmap = frameBitmaps_[nextFrameIndex_]; if (!bitmap.getPixels()) { // We haven't decoded this frame yet const SkImageInfo info = codec_->getInfo().makeColorType(kN32_SkColorType); @@ -245,15 +263,13 @@ sk_sp MultiFrameCodec::GetNextFrameImage() { } } - std::unique_ptr resourceContext = ResourceContext::Acquire(); - GrContext* context = resourceContext->Get(); - if (context) { + if (resourceContext) { 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(context, pixmap, false, - dstColorSpace.get()); + return SkImage::MakeCrossContextFromPixmap(resourceContext.get(), 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 @@ -264,19 +280,22 @@ 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(); + sk_sp skImage = GetNextFrameImage(resourceContext); if (skImage) { fxl::RefPtr image = CanvasImage::Create(); - image->set_image(skImage); + image->set_image({skImage, std::move(unref_queue)}); frameInfo = fxl::MakeRefCounted( std::move(image), frameInfos_[nextFrameIndex_].fDuration); } nextFrameIndex_ = (nextFrameIndex_ + 1) % frameInfos_.size(); - Threads::UI()->PostTask(fxl::MakeCopyable( - [ callback = std::move(callback), frameInfo, trace_id ]() mutable { + ui_task_runner->PostTask(fxl::MakeCopyable( + [callback = std::move(callback), frameInfo, trace_id]() mutable { InvokeNextFrameCallback(frameInfo, std::move(callback), trace_id); })); @@ -293,13 +312,20 @@ Dart_Handle MultiFrameCodec::getNextFrame(Dart_Handle callback_handle) { return ToDart("Callback must be a function"); } - Threads::IO()->PostTask(fxl::MakeCopyable([ - callback = std::make_unique( - tonic::DartState::Current(), callback_handle), - this, trace_id - ]() mutable { - GetNextFrameAndInvokeCallback(std::move(callback), trace_id); - })); + 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); + })); return Dart_Null(); } diff --git a/lib/ui/painting/codec.h b/lib/ui/painting/codec.h index 98e5bc56df375df084f4e92b24053f8850dc26c6..9fdce1a8c1a331ae7fca8571febb6c2eef948460 100644 --- a/lib/ui/painting/codec.h +++ b/lib/ui/painting/codec.h @@ -43,11 +43,16 @@ class MultiFrameCodec : public Codec { private: MultiFrameCodec(std::unique_ptr codec); + ~MultiFrameCodec() {} - sk_sp GetNextFrameImage(); + sk_sp GetNextFrameImage(fml::WeakPtr resourceContext); + 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 f6bb864627740128924aadda3a5c9b48126aced0..52ccd63f3f5d334f034db74436b1890dffd76c77 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(SkGradientShader::MakeLinear( + set_shader(UIDartState::CreateGPUObject(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(SkGradientShader::MakeRadial( + set_shader(UIDartState::CreateGPUObject(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() : Shader(nullptr) {} +CanvasGradient::CanvasGradient() = default; -CanvasGradient::~CanvasGradient() {} +CanvasGradient::~CanvasGradient() = default; } // namespace blink diff --git a/lib/ui/painting/image.cc b/lib/ui/painting/image.cc index 42e733241c990c72f748ef2cd44b325149da2984..a1b9b45cdc86303ace272d418fc0d09a9c9569eb 100644 --- a/lib/ui/painting/image.cc +++ b/lib/ui/painting/image.cc @@ -4,9 +4,7 @@ #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" @@ -30,13 +28,9 @@ void CanvasImage::RegisterNatives(tonic::DartLibraryNatives* natives) { natives->Register({FOR_EACH_BINDING(DART_REGISTER_NATIVE)}); } -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_); -} +CanvasImage::~CanvasImage() = default; Dart_Handle CanvasImage::toByteData(int format, int quality, @@ -49,8 +43,8 @@ void CanvasImage::dispose() { } size_t CanvasImage::GetAllocationSize() { - if (image_) { - return image_->width() * image_->height() * 4; + if (auto image = image_.get()) { + 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 a7ed4298506f54143451da5d5be232d834838b35..aeec2a0149c73b64412e8b68dea0135f3ae63d07 100644 --- a/lib/ui/painting/image.h +++ b/lib/ui/painting/image.h @@ -5,6 +5,8 @@ #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" @@ -25,13 +27,18 @@ class CanvasImage final : public fxl::RefCountedThreadSafe, return fxl::MakeRefCounted(); } - int width() { return image_->width(); } - int height() { return image_->height(); } + int width() { return image_.get()->width(); } + + int height() { return image_.get()->height(); } + Dart_Handle toByteData(int format, int quality, Dart_Handle callback); + void dispose(); - const sk_sp& image() const { return image_; } - void set_image(sk_sp image) { image_ = std::move(image); } + sk_sp image() const { return image_.get(); } + void set_image(flow::SkiaGPUObject image) { + image_ = std::move(image); + } virtual size_t GetAllocationSize() override; @@ -40,7 +47,7 @@ class CanvasImage final : public fxl::RefCountedThreadSafe, private: CanvasImage(); - sk_sp image_; + flow::SkiaGPUObject image_; }; } // namespace blink diff --git a/lib/ui/painting/image_encoding.cc b/lib/ui/painting/image_encoding.cc index f356e955f674558e76126e5dfb6b792693048e64..f010fce893d3e4418277b8951b323ab96e6ef558 100644 --- a/lib/ui/painting/image_encoding.cc +++ b/lib/ui/painting/image_encoding.cc @@ -4,13 +4,15 @@ #include "flutter/lib/ui/painting/image_encoding.h" -#include "flutter/common/threads.h" +#include +#include + +#include "flutter/common/task_runners.h" #include "flutter/lib/ui/painting/image.h" -#include "flutter/lib/ui/painting/resource_context.h" +#include "flutter/lib/ui/ui_dart_state.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" @@ -52,10 +54,11 @@ void EncodeImageAndInvokeDataCallback( std::unique_ptr callback, sk_sp image, SkEncodedImageFormat format, - int quality) { + int quality, + fxl::RefPtr ui_task_runner) { sk_sp encoded = EncodeImage(std::move(image), format, quality); - Threads::UI()->PostTask( + ui_task_runner->PostTask( fxl::MakeCopyable([callback = std::move(callback), encoded]() mutable { InvokeDataCallback(std::move(callback), std::move(encoded)); })); @@ -101,10 +104,14 @@ Dart_Handle EncodeImage(CanvasImage* canvas_image, tonic::DartState::Current(), callback_handle); sk_sp image = canvas_image->image(); - Threads::IO()->PostTask(fxl::MakeCopyable( - [callback = std::move(callback), image, image_format, quality]() mutable { + 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 { EncodeImageAndInvokeDataCallback(std::move(callback), std::move(image), - image_format, quality); + image_format, quality, + std::move(ui_task_runner)); })); return Dart_Null(); diff --git a/lib/ui/painting/image_shader.cc b/lib/ui/painting/image_shader.cc index 0fabd134c737c45a67f5e7eed47568eec5c4c5cd..a4ddbba0ea24b151b3fe290a80a57f04cde44ce4 100644 --- a/lib/ui/painting/image_shader.cc +++ b/lib/ui/painting/image_shader.cc @@ -4,6 +4,7 @@ #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" @@ -37,15 +38,17 @@ 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(image->image()->makeShader(tmx, tmy, &sk_matrix)); + set_shader(UIDartState::CreateGPUObject( + image->image()->makeShader(tmx, tmy, &sk_matrix))); } -ImageShader::ImageShader() : Shader(nullptr) {} +ImageShader::ImageShader() = default; -ImageShader::~ImageShader() {} +ImageShader::~ImageShader() = default; } // namespace blink diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 89ddbf5f41bb0196d0be2113220cb8b1e2883e95..34f92b8c315fdfae9aa9cb2e097e40e8ea8df044 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -4,9 +4,8 @@ #include "flutter/lib/ui/painting/picture.h" -#include "flutter/common/threads.h" #include "flutter/lib/ui/painting/canvas.h" -#include "flutter/lib/ui/painting/utils.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" @@ -23,24 +22,20 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Picture); DART_BIND_ALL(Picture, FOR_EACH_BINDING) -fxl::RefPtr Picture::Create(sk_sp picture) { +fxl::RefPtr Picture::Create(flow::SkiaGPUObject picture) { return fxl::MakeRefCounted(std::move(picture)); } -Picture::Picture(sk_sp picture) : picture_(std::move(picture)) {} +Picture::Picture(flow::SkiaGPUObject picture) + : picture_(std::move(picture)) {} -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_); -} +Picture::~Picture() = default; fxl::RefPtr Picture::toImage(int width, int height) { fxl::RefPtr image = CanvasImage::Create(); - // 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())); + image->set_image(UIDartState::CreateGPUObject(SkImage::MakeFromPicture( + picture_.get(), SkISize::Make(width, height), nullptr, nullptr, + SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB()))); return image; } @@ -49,8 +44,8 @@ void Picture::dispose() { } size_t Picture::GetAllocationSize() { - if (picture_) { - return picture_->approximateBytesUsed(); + if (auto picture = picture_.get()) { + return picture->approximateBytesUsed(); } else { return sizeof(Picture); } diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h index 4a26d01c08374fd9329fc49cdc4b94983c7653bc..d916086b02f0217fbe444e46ca4db59ffae89239 100644 --- a/lib/ui/painting/picture.h +++ b/lib/ui/painting/picture.h @@ -5,6 +5,7 @@ #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" @@ -23,9 +24,9 @@ class Picture : public fxl::RefCountedThreadSafe, public: ~Picture() override; - static fxl::RefPtr Create(sk_sp picture); + static fxl::RefPtr Create(flow::SkiaGPUObject picture); - const sk_sp& picture() const { return picture_; } + sk_sp picture() const { return picture_.get(); } fxl::RefPtr toImage(int width, int height); @@ -36,9 +37,9 @@ class Picture : public fxl::RefCountedThreadSafe, static void RegisterNatives(tonic::DartLibraryNatives* natives); private: - explicit Picture(sk_sp picture); + explicit Picture(flow::SkiaGPUObject picture); - sk_sp picture_; + flow::SkiaGPUObject picture_; }; } // namespace blink diff --git a/lib/ui/painting/picture_recorder.cc b/lib/ui/painting/picture_recorder.cc index adc73c0043920e09f34a2c2f44eb595e701944bc..e870e400a72308669c268f76064159cccd813107 100644 --- a/lib/ui/painting/picture_recorder.cc +++ b/lib/ui/painting/picture_recorder.cc @@ -50,8 +50,9 @@ SkCanvas* PictureRecorder::BeginRecording(SkRect bounds) { fxl::RefPtr PictureRecorder::endRecording() { if (!isRecording()) return nullptr; - fxl::RefPtr picture = - Picture::Create(picture_recorder_.finishRecordingAsPicture()); + + fxl::RefPtr picture = Picture::Create(UIDartState::CreateGPUObject( + 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 deleted file mode 100644 index 1b9f71548c15fb943d0f59148280fd79cc07deb9..0000000000000000000000000000000000000000 --- a/lib/ui/painting/resource_context.cc +++ /dev/null @@ -1,51 +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. - -#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 deleted file mode 100644 index 627b2053c2df9907b58361147897b7ff1b264246..0000000000000000000000000000000000000000 --- a/lib/ui/painting/resource_context.h +++ /dev/null @@ -1,60 +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. - -#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 d7d8ccf20aefc0882885be54079e4c387c676829..7999b84dfcc29eb14c7746087feef5cfbfe49581 100644 --- a/lib/ui/painting/shader.cc +++ b/lib/ui/painting/shader.cc @@ -4,19 +4,15 @@ #include "flutter/lib/ui/painting/shader.h" -#include "flutter/common/threads.h" -#include "flutter/lib/ui/painting/utils.h" +#include "flutter/lib/ui/ui_dart_state.h" namespace blink { IMPLEMENT_WRAPPERTYPEINFO(ui, Shader); -Shader::Shader(sk_sp shader) : shader_(shader) {} +Shader::Shader(flow::SkiaGPUObject shader) + : shader_(std::move(shader)) {} -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_); -} +Shader::~Shader() = default; } // namespace blink diff --git a/lib/ui/painting/shader.h b/lib/ui/painting/shader.h index 9c0f3c601db56fb22ca2e5abb7173600d3f0e07f..205197250eb8445177473ee68f2ba0b1e79d9ec8 100644 --- a/lib/ui/painting/shader.h +++ b/lib/ui/painting/shader.h @@ -5,6 +5,8 @@ #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" @@ -18,14 +20,17 @@ class Shader : public fxl::RefCountedThreadSafe, public: ~Shader() override; - const sk_sp& shader() { return shader_; } - void set_shader(sk_sp shader) { shader_ = std::move(shader); } + sk_sp shader() { return shader_.get(); } + + void set_shader(flow::SkiaGPUObject shader) { + shader_ = std::move(shader); + } protected: - Shader(sk_sp shader); + Shader(flow::SkiaGPUObject shader = {}); private: - sk_sp shader_; + flow::SkiaGPUObject shader_; }; } // namespace blink diff --git a/lib/ui/painting/utils.cc b/lib/ui/painting/utils.cc deleted file mode 100644 index b3f87135ac0a8d8b9bea1208b6c8863119b0812c..0000000000000000000000000000000000000000 --- a/lib/ui/painting/utils.cc +++ /dev/null @@ -1,46 +0,0 @@ -// 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 deleted file mode 100644 index 02782c67962bc5328813bbca9f4e40ac7a38fa6c..0000000000000000000000000000000000000000 --- a/lib/ui/painting/utils.h +++ /dev/null @@ -1,38 +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. - -#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 d6407f9ed42e116de5a0537ac83b1580bf034b66..248468cc9701d9200e87e3637aa127eb7030dcf8 100644 --- a/lib/ui/text/font_collection.cc +++ b/lib/ui/text/font_collection.cc @@ -34,15 +34,9 @@ std::shared_ptr FontCollection::GetFontCollection() const { return collection_; } -void FontCollection::RegisterFontsFromAssetProvider( - fxl::RefPtr asset_provider) { - - if (!asset_provider){ - return; - } - +void FontCollection::RegisterFonts(const AssetManager& asset_manager) { std::vector manifest_data; - if (!asset_provider->GetAsBuffer("FontManifest.json", &manifest_data)) { + if (!asset_manager.GetAsBuffer("FontManifest.json", &manifest_data)) { FXL_DLOG(WARNING) << "Could not find the font manifest in the asset store."; return; } @@ -92,8 +86,8 @@ void FontCollection::RegisterFontsFromAssetProvider( // TODO: Handle weights and styles. std::vector font_data; - if (asset_provider->GetAsBuffer(font_asset->value.GetString(), - &font_data)) { + if (asset_manager.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 fb393b1582b792ae097037264732ac5f3e3fa628..ea9c2f46a96a0c22ceced0ae0ad369275d8845ba 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_provider.h" + +#include "flutter/assets/asset_manager.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,7 +21,8 @@ class FontCollection { std::shared_ptr GetFontCollection() const; - void RegisterFontsFromAssetProvider(fxl::RefPtr asset_provider); + void RegisterFonts(const AssetManager& asset_manager); + void RegisterTestFonts(); private: diff --git a/lib/ui/text/paragraph.cc b/lib/ui/text/paragraph.cc index 858ccd01d4ef67b791d15e8f7c8bd64c372162b3..fd00f6f51b3a352a6661e47d516ff6de60109ee8 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/threads.h" +#include "flutter/common/task_runners.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,7 +53,8 @@ Paragraph::Paragraph(std::unique_ptr paragraph) Paragraph::~Paragraph() { if (m_renderView) { RenderView* renderView = m_renderView.leakPtr(); - Threads::UI()->PostTask([renderView]() { renderView->destroy(); }); + destruction_task_runner_->PostTask( + [renderView]() { renderView->destroy(); }); } } diff --git a/lib/ui/text/paragraph.h b/lib/ui/text/paragraph.h index 1b2019373553af8a6d01c9cad52dd08d6d7b5ce6..b3a943209ab4c2a61941388b06377bd9f03158f9 100644 --- a/lib/ui/text/paragraph.h +++ b/lib/ui/text/paragraph.h @@ -5,6 +5,7 @@ #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" @@ -66,6 +67,10 @@ 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 44d05053ba34214278c46f5d292a84cb3930e5ec..b987e3fde62722a98d956c9908f91d4355cf8a04 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/threads.h" +#include "flutter/common/task_runners.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,9 +205,11 @@ fxl::RefPtr ParagraphBuilder::create( double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale) { - return fxl::MakeRefCounted(encoded, fontFamily, fontSize, - lineHeight, ellipsis, locale); + const std::string& locale, + bool use_blink) { + return fxl::MakeRefCounted( + encoded, fontFamily, fontSize, lineHeight, ellipsis, locale, + UIDartState::Current()->use_blink()); } ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, @@ -215,8 +217,10 @@ ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale) { - if (!Settings::Get().using_blink) { + const std::string& locale, + bool use_blink) + : m_useBlink(use_blink) { + if (!m_useBlink) { int32_t mask = encoded[0]; txt::ParagraphStyle style; if (mask & psTextAlignMask) @@ -275,7 +279,8 @@ ParagraphBuilder::ParagraphBuilder(tonic::Int32List& encoded, ParagraphBuilder::~ParagraphBuilder() { if (m_renderView) { RenderView* renderView = m_renderView.leakPtr(); - Threads::UI()->PostTask([renderView]() { renderView->destroy(); }); + destruction_task_runner_->PostTask( + [renderView]() { renderView->destroy(); }); } } @@ -290,7 +295,7 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, int32_t mask = encoded[0]; - if (!Settings::Get().using_blink) { + if (!m_useBlink) { // Set to use the properties of the previous style if the property is not // explicitly given. txt::TextStyle style = m_paragraphBuilder->PeekStyle(); @@ -423,7 +428,7 @@ void ParagraphBuilder::pushStyle(tonic::Int32List& encoded, } void ParagraphBuilder::pop() { - if (!Settings::Get().using_blink) { + if (!m_useBlink) { m_paragraphBuilder->Pop(); } else { // Blink Version. @@ -445,7 +450,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 (!Settings::Get().using_blink) { + if (!m_useBlink) { m_paragraphBuilder->AddText(text); } else { // Blink Version. @@ -464,7 +469,7 @@ Dart_Handle ParagraphBuilder::addText(const std::u16string& text) { fxl::RefPtr ParagraphBuilder::build() { m_currentRenderObject = nullptr; - if (!Settings::Get().using_blink) { + if (!m_useBlink) { 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 37a1e9a3e74cfc1f793ba8e105ac5f9ff9fa99e9..1c38d98696def5d26fbf1a1782b3abb02e17fd38 100644 --- a/lib/ui/text/paragraph_builder.h +++ b/lib/ui/text/paragraph_builder.h @@ -32,7 +32,8 @@ class ParagraphBuilder : public fxl::RefCountedThreadSafe, double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale); + const std::string& locale, + bool use_blink); ~ParagraphBuilder() override; @@ -58,14 +59,20 @@ class ParagraphBuilder : public fxl::RefCountedThreadSafe, double fontSize, double lineHeight, const std::u16string& ellipsis, - const std::string& locale); + const std::string& locale, + bool use_blink); 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 c7752c0a7c7573fe959229fc2ab76f13b67c17fc..5c50f047afa33f904c310b8b2fbfb66fc116aeab 100644 --- a/lib/ui/text/paragraph_impl_blink.cc +++ b/lib/ui/text/paragraph_impl_blink.cc @@ -4,7 +4,6 @@ #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" @@ -30,7 +29,8 @@ ParagraphImplBlink::ParagraphImplBlink(PassOwnPtr renderView) ParagraphImplBlink::~ParagraphImplBlink() { if (m_renderView) { RenderView* renderView = m_renderView.leakPtr(); - Threads::UI()->PostTask([renderView]() { renderView->destroy(); }); + destruction_task_runner_->PostTask( + [renderView]() { renderView->destroy(); }); } } diff --git a/lib/ui/text/paragraph_impl_blink.h b/lib/ui/text/paragraph_impl_blink.h index 79d89ad47196251d8e759d14dc7f6312356d5de2..ebd80f8dd5382c3a468e9a4466c0e4ef67c475be 100644 --- a/lib/ui/text/paragraph_impl_blink.h +++ b/lib/ui/text/paragraph_impl_blink.h @@ -5,6 +5,7 @@ #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" @@ -41,6 +42,10 @@ 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 de8d8ff0b2fc3414c6836b070ab168fd085cdea5..28c6ea19a8157507565094e36cbb9906005df95b 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/threads.h" +#include "flutter/common/task_runners.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 3bdf21e6a1a9375d3115651fb0569edbd3088227..8ef7ca98fd7581254bf280fe7e7d2f613f4da992 100644 --- a/lib/ui/ui_dart_state.cc +++ b/lib/ui/ui_dart_state.cc @@ -4,6 +4,7 @@ #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" @@ -12,34 +13,44 @@ using tonic::ToDart; namespace blink { -IsolateClient::~IsolateClient() {} - -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)) {} +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 */); +} 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(); + AddOrRemoveTaskObserver(false /* remove */); } -UIDartState* UIDartState::CreateForChildIsolate() { - return new UIDartState(isolate_client_, nullptr); +const std::string& UIDartState::GetAdvisoryScriptURI() const { + return advisory_script_uri_; +} + +const std::string& UIDartState::GetAdvisoryScriptEntrypoint() const { + return advisory_script_entrypoint_; } void UIDartState::DidSetIsolate() { - FXL_DCHECK(!debug_name_prefix_.empty()); main_port_ = Dart_GetMainPortId(); std::ostringstream debug_name; - debug_name << debug_name_prefix_ << "$main-" << main_port_; + // main.dart$main-1234 + debug_name << advisory_script_uri_ << "$" << advisory_script_entrypoint_ + << "-" << main_port_; debug_name_ = debug_name.str(); } @@ -55,8 +66,48 @@ PassRefPtr UIDartState::font_selector() { return font_selector_; } -void UIDartState::set_debug_name_prefix(const std::string& debug_name_prefix) { - debug_name_prefix_ = debug_name_prefix; +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_; } } // namespace blink diff --git a/lib/ui/ui_dart_state.h b/lib/ui/ui_dart_state.h index 0f7f9343d4958c183a7f6d13ec0086c0d6771f73..a5c78c167181512f993f53a3d69e3a1b1eeaeec2 100644 --- a/lib/ui/ui_dart_state.h +++ b/lib/ui/ui_dart_state.h @@ -5,65 +5,106 @@ #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(); - 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 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; } + + 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; private: void DidSetIsolate() override; - IsolateClient* isolate_client_; - Dart_Port main_port_; - std::string debug_name_prefix_; + 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; std::string debug_name_; std::unique_ptr window_; RefPtr font_selector_; - bool is_controller_state_; - bool shutting_down_ = false; + fxl::RefPtr skia_unref_queue_; + tonic::DartMicrotaskQueue microtask_queue_; + fml::WeakPtrFactory weak_factory_; + + void AddOrRemoveTaskObserver(bool add); + + bool use_blink_ = false; }; } // namespace blink diff --git a/lib/ui/window/platform_message_response_dart.cc b/lib/ui/window/platform_message_response_dart.cc index 065159b79713bc01a73ffd7cd324235c7fdca094..2cca2fd179888faa7f1897f969aaa2fa14a33bb3 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/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/lib/ui/window/window.h" #include "lib/fxl/functional/make_copyable.h" #include "lib/tonic/dart_state.h" @@ -43,12 +43,14 @@ Dart_Handle WrapByteData(std::vector data) { } // anonymous namespace PlatformMessageResponseDart::PlatformMessageResponseDart( - tonic::DartPersistentValue callback) - : callback_(std::move(callback)) {} + tonic::DartPersistentValue callback, + fxl::RefPtr ui_task_runner) + : callback_(std::move(callback)), + ui_task_runner_(std::move(ui_task_runner)) {} PlatformMessageResponseDart::~PlatformMessageResponseDart() { if (!callback_.is_empty()) { - Threads::UI()->PostTask( + ui_task_runner_->PostTask( fxl::MakeCopyable([callback = std::move(callback_)]() mutable { callback.Clear(); })); @@ -60,7 +62,7 @@ void PlatformMessageResponseDart::Complete(std::vector data) { return; FXL_DCHECK(!is_complete_); is_complete_ = true; - Threads::UI()->PostTask(fxl::MakeCopyable( + ui_task_runner_->PostTask(fxl::MakeCopyable( [ callback = std::move(callback_), data = std::move(data) ]() mutable { tonic::DartState* dart_state = callback.dart_state().get(); if (!dart_state) @@ -77,7 +79,7 @@ void PlatformMessageResponseDart::CompleteEmpty() { return; FXL_DCHECK(!is_complete_); is_complete_ = true; - Threads::UI()->PostTask( + ui_task_runner_->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 51c55a930014b7865cf2f32b0a19357e35fabb6c..67bfb3d35969131c438f0522888870bc63416117 100644 --- a/lib/ui/window/platform_message_response_dart.h +++ b/lib/ui/window/platform_message_response_dart.h @@ -5,6 +5,7 @@ #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" @@ -19,10 +20,13 @@ class PlatformMessageResponseDart : public PlatformMessageResponse { void CompleteEmpty() override; protected: - explicit PlatformMessageResponseDart(tonic::DartPersistentValue callback); + explicit PlatformMessageResponseDart( + tonic::DartPersistentValue callback, + fxl::RefPtr ui_task_runner); ~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 1e443ae8c140424c4f73a5204dd2ebb5bf214903..5085d06f42724b3aca48fac50edb163ee24bf46a 100644 --- a/lib/ui/window/viewport_metrics.h +++ b/lib/ui/window/viewport_metrics.h @@ -23,6 +23,25 @@ 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 e12e03f10d01f749d88e97a170674cd6a944a480..4cce1cc5903b0a92cae5866933049616a05bbfc8 100644 --- a/lib/ui/window/window.cc +++ b/lib/ui/window/window.cc @@ -63,7 +63,8 @@ void SendPlatformMessage(Dart_Handle window, fxl::RefPtr response; if (!Dart_IsNull(callback)) { response = fxl::MakeRefCounted( - tonic::DartPersistentValue(dart_state, callback)); + tonic::DartPersistentValue(dart_state, callback), + dart_state->GetTaskRunners().GetUITaskRunner()); } if (Dart_IsNull(data.dart_handle())) { UIDartState::Current()->window()->client()->HandlePlatformMessage( @@ -254,7 +255,7 @@ void Window::BeginFrame(fxl::TimePoint frameTime) { Dart_NewInteger(microseconds), }); - tonic::DartMicrotaskQueue::GetForCurrentThread()->RunMicrotasks(); + UIDartState::Current()->FlushMicrotasksNow(); DartInvokeField(library_.value(), "_drawFrame", {}); } diff --git a/lib/ui/window/window.h b/lib/ui/window/window.h index ef0d7ef863a0e9d39c01f12827569804308f3471..2feeccb65f9ccb6145ce28854d8b825110d5aded 100644 --- a/lib/ui/window/window.h +++ b/lib/ui/window/window.h @@ -13,6 +13,7 @@ #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; @@ -35,12 +36,14 @@ class WindowClient { virtual ~WindowClient(); }; -class Window { +class Window final { 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 dea8a8906d0312c9a68a1327d754e1b515365634..455d7e228168f40a18cec60ec1d9a1ed398a3a5f 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -4,6 +4,7 @@ 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" @@ -37,9 +38,7 @@ source_set("embedded_resources_cc") { deps = [ ":gen_embedded_resources_cc", ] - public_configs = [ - "$flutter_root:config", - ] + public_configs = [ "$flutter_root:config" ] } source_set("test_font") { @@ -50,9 +49,7 @@ 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 @@ -63,16 +60,19 @@ source_set("test_font") { } source_set("runtime") { - sources = [ "asset_font_selector.cc", "asset_font_selector.h", - "dart_controller.cc", - "dart_controller.h", - "dart_init.cc", - "dart_init.h", + "dart_isolate.cc", + "dart_isolate.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", - "runtime_init.cc", - "runtime_init.h", + "service_protocol.cc", + "service_protocol.h", "start_up.cc", "start_up.h", "test_font_selector.cc", @@ -92,25 +92,24 @@ 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 @@ -119,3 +118,28 @@ 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 abf4bf9874ddd29aa4c004c2cfaffad968f39afc..2a43f39e3a89beb5e37bab693484ca71e9fbb92b 100644 --- a/runtime/asset_font_selector.cc +++ b/runtime/asset_font_selector.cc @@ -80,27 +80,15 @@ struct FontMatcher { } // namespace -void AssetFontSelector::Install( - fxl::RefPtr asset_provider) { +void AssetFontSelector::Install(fxl::RefPtr asset_manager) { RefPtr font_selector = - adoptRef(new AssetFontSelector(std::move(asset_provider))); + adoptRef(new AssetFontSelector(std::move(asset_manager))); font_selector->parseFontManifest(); UIDartState::Current()->set_font_selector(font_selector); } -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(fxl::RefPtr asset_manager) + : asset_manager_(std::move(asset_manager)) {} AssetFontSelector::~AssetFontSelector() {} @@ -118,12 +106,9 @@ AssetFontSelector::FlutterFontAttributes::~FlutterFontAttributes() {} void AssetFontSelector::parseFontManifest() { std::vector font_manifest_data; - if (!asset_provider_ || - !asset_provider_->GetAsBuffer(kFontManifestAssetPath, - &font_manifest_data)) { - if (!asset_store_ || - !asset_store_->GetAsBuffer(kFontManifestAssetPath, &font_manifest_data)) - return; + if (!asset_manager_->GetAsBuffer(kFontManifestAssetPath, + &font_manifest_data)) { + return; } rapidjson::Document document; @@ -239,13 +224,8 @@ sk_sp AssetFontSelector::getTypefaceAsset( } std::unique_ptr typeface_asset(new TypefaceAsset); - 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; - } + if (!asset_manager_->GetAsBuffer(asset_path, &typeface_asset->data)) { + return nullptr; } sk_sp font_mgr(SkFontMgr::RefDefault()); diff --git a/runtime/asset_font_selector.h b/runtime/asset_font_selector.h index 921c0472dba784f66ee303098e29c99c2a44e0f6..8d7e946d89e7e77a75ad217c3bbe539cc31acc7b 100644 --- a/runtime/asset_font_selector.h +++ b/runtime/asset_font_selector.h @@ -8,7 +8,7 @@ #include #include -#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/assets/asset_manager.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,11 +24,7 @@ class AssetFontSelector : public FontSelector { ~AssetFontSelector() override; - 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); + static void Install(fxl::RefPtr asset_manager); PassRefPtr getFontData(const FontDescription& font_description, const AtomicString& family_name) override; @@ -44,19 +40,14 @@ class AssetFontSelector : public FontSelector { private: struct TypefaceAsset; - explicit AssetFontSelector( - fxl::RefPtr asset_provider); - - explicit AssetFontSelector(fxl::RefPtr asset_store); + explicit AssetFontSelector(fxl::RefPtr asset_manager); void parseFontManifest(); sk_sp getTypefaceAsset(const FontDescription& font_description, const AtomicString& family_name); - fxl::RefPtr asset_provider_; - - fxl::RefPtr asset_store_; + fxl::RefPtr asset_manager_; HashMap> font_family_map_; diff --git a/runtime/dart_controller.cc b/runtime/dart_controller.cc deleted file mode 100644 index 84cfceeaecc10ad7acfe73fac3d71f9f1fc4efc7..0000000000000000000000000000000000000000 --- a/runtime/dart_controller.cc +++ /dev/null @@ -1,250 +0,0 @@ -// 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 deleted file mode 100644 index 4b11a8660b7e770646ab3954ddb10b62b42af612..0000000000000000000000000000000000000000 --- a/runtime/dart_controller.h +++ /dev/null @@ -1,55 +0,0 @@ -// 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 deleted file mode 100644 index e3d88322a48825f300210af15ee0b2776dabacf9..0000000000000000000000000000000000000000 --- a/runtime/dart_init.cc +++ /dev/null @@ -1,725 +0,0 @@ -// 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 deleted file mode 100644 index 99c8fe89137e32b513ab5790004cfee58428a587..0000000000000000000000000000000000000000 --- a/runtime/dart_init.h +++ /dev/null @@ -1,64 +0,0 @@ -// 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 new file mode 100644 index 0000000000000000000000000000000000000000..c5fd770b1b40cf960a6973241196914de23f0eb2 --- /dev/null +++ b/runtime/dart_isolate.cc @@ -0,0 +1,715 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..13d573ebe333f141852e07513ffcae41a912fb84 --- /dev/null +++ b/runtime/dart_isolate.h @@ -0,0 +1,152 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..d8f2e02382da16f69d61000f4abb17a8e11c7fa6 --- /dev/null +++ b/runtime/dart_isolate_unittests.cc @@ -0,0 +1,103 @@ +// 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 9edd663feb6bdde3b2b637c6ec068a3c97bd5f08..59a02e2e9d4951a685f7ccfee961e46e1bd0abf7 100644 --- a/runtime/dart_service_isolate.h +++ b/runtime/dart_service_isolate.h @@ -13,8 +13,6 @@ 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 new file mode 100644 index 0000000000000000000000000000000000000000..5d759257d1d4bd270cc97dcd2af41320d99d1963 --- /dev/null +++ b/runtime/dart_snapshot.cc @@ -0,0 +1,159 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..4f04765b4f5a9752487fc1150a0dc5be70d428ba --- /dev/null +++ b/runtime/dart_snapshot.h @@ -0,0 +1,57 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..c39233ac8334aa3702a4303ab4b463efc26d55c1 --- /dev/null +++ b/runtime/dart_snapshot_buffer.cc @@ -0,0 +1,72 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..675946c0ca63fcb0709766fe6f9da123c241c7a1 --- /dev/null +++ b/runtime/dart_snapshot_buffer.h @@ -0,0 +1,34 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..bb4677907858348a550e1dacb0c7b6a4906bee02 --- /dev/null +++ b/runtime/dart_vm.cc @@ -0,0 +1,472 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..e8feb9ba1de92de3e2c3e3e1d4ba460becff360b --- /dev/null +++ b/runtime/dart_vm.h @@ -0,0 +1,75 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..5b2f5e6ee8299c3c8a4baa88bb34ef3241c19738 --- /dev/null +++ b/runtime/dart_vm_unittests.cc @@ -0,0 +1,21 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..552dfbe3449029e0d5ccdb608521106fe02653fc --- /dev/null +++ b/runtime/fixtures/simple_main.dart @@ -0,0 +1,7 @@ +// 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 75796cd68697e6fd0b7a196ab0a5bc0537cfa768..e7a8ab525329a413677ef86b28784ab90cad313d 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -4,192 +4,248 @@ #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; +#ifdef ERROR +#undef ERROR +#endif namespace blink { -std::unique_ptr RuntimeController::Create( - RuntimeDelegate* client) { - return std::unique_ptr(new RuntimeController(client)); +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_ = {}; + } } -RuntimeController::RuntimeController(RuntimeDelegate* client) - : client_(client) {} - -RuntimeController::~RuntimeController() {} +std::unique_ptr RuntimeController::Clone() const { + return std::unique_ptr(new RuntimeController( + client_, // + vm_, // + task_runners_, // + resource_context_, // + unref_queue_, // + window_data_ // + )); +} -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_); +bool RuntimeController::FlushRuntimeStateToIsolate() { + return SetViewportMetrics(window_data_.viewport_metrics) && + SetLocale(window_data_.language_code, window_data_.country_code) && + SetSemanticsEnabled(window_data_.semantics_enabled); +} - 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::SetViewportMetrics(const ViewportMetrics& metrics) { + window_data_.viewport_metrics = metrics; - 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->UpdateWindowMetrics(metrics); + return true; + } + return false; +} - Window* window = GetWindow(); +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; - window->UpdateLocale(language_code_, country_code_); + if (auto window = GetWindowIfAvailable()) { + window->UpdateLocale(window_data_.language_code, window_data_.country_code); + return true; + } - if (semantics_enabled_) - window->UpdateSemanticsEnabled(semantics_enabled_); + return false; } -void RuntimeController::SetViewportMetrics(const ViewportMetrics& metrics) { - GetWindow()->UpdateWindowMetrics(metrics); -} +bool RuntimeController::SetUserSettingsData(const std::string& data) { + window_data_.user_settings_data = data; -void RuntimeController::SetLocale(const std::string& language_code, - const std::string& country_code) { - if (language_code_ == language_code && country_code_ == country_code) - return; + if (auto window = GetWindowIfAvailable()) { + window->UpdateUserSettingsData(window_data_.user_settings_data); + return true; + } - language_code_ = language_code; - country_code_ = country_code; - GetWindow()->UpdateLocale(language_code_, country_code_); + return false; } -void RuntimeController::SetUserSettingsData(const std::string& data) { - if (user_settings_data_ == data) - return; - user_settings_data_ = data; - GetWindow()->UpdateUserSettingsData(user_settings_data_); -} +bool RuntimeController::SetSemanticsEnabled(bool enabled) { + window_data_.semantics_enabled = enabled; + + if (auto window = GetWindowIfAvailable()) { + window->UpdateSemanticsEnabled(window_data_.semantics_enabled); + return true; + } -void RuntimeController::SetSemanticsEnabled(bool enabled) { - if (semantics_enabled_ == enabled) - return; - semantics_enabled_ = enabled; - GetWindow()->UpdateSemanticsEnabled(semantics_enabled_); + return false; } -void RuntimeController::BeginFrame(fxl::TimePoint frame_time) { - GetWindow()->BeginFrame(frame_time); +bool RuntimeController::BeginFrame(fxl::TimePoint frame_time) { + if (auto window = GetWindowIfAvailable()) { + window->BeginFrame(frame_time); + return true; + } + return false; } -void RuntimeController::NotifyIdle(int64_t deadline) { - UIDartState* dart_state = dart_controller_->dart_state(); - if (!dart_state) { - return; +bool RuntimeController::NotifyIdle(int64_t deadline) { + if (!root_isolate_) { + return false; } - DartState::Scope scope(dart_state); + + tonic::DartState::Scope scope(root_isolate_.get()); Dart_NotifyIdle(deadline); + return true; } -void RuntimeController::DispatchPlatformMessage( +bool RuntimeController::DispatchPlatformMessage( fxl::RefPtr message) { - TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", "mode", - "basic"); - GetWindow()->DispatchPlatformMessage(std::move(message)); + if (auto window = GetWindowIfAvailable()) { + TRACE_EVENT1("flutter", "RuntimeController::DispatchPlatformMessage", + "mode", "basic"); + window->DispatchPlatformMessage(std::move(message)); + return true; + } + return false; } -void RuntimeController::DispatchPointerDataPacket( +bool RuntimeController::DispatchPointerDataPacket( const PointerDataPacket& packet) { - TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", - "mode", "basic"); - GetWindow()->DispatchPointerDataPacket(packet); + if (auto window = GetWindowIfAvailable()) { + TRACE_EVENT1("flutter", "RuntimeController::DispatchPointerDataPacket", + "mode", "basic"); + window->DispatchPointerDataPacket(packet); + return true; + } + return false; } -void RuntimeController::DispatchSemanticsAction(int32_t id, +bool RuntimeController::DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector args) { TRACE_EVENT1("flutter", "RuntimeController::DispatchSemanticsAction", "mode", "basic"); - GetWindow()->DispatchSemanticsAction(id, action, std::move(args)); + if (auto window = GetWindowIfAvailable()) { + window->DispatchSemanticsAction(id, action, std::move(args)); + return true; + } + return false; } -Window* RuntimeController::GetWindow() { - return dart_controller_->dart_state()->window(); +Window* RuntimeController::GetWindowIfAvailable() { + return root_isolate_ ? root_isolate_->window() : nullptr; } 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 (semantics_enabled_) - client_->UpdateSemantics(update->takeNodes()); + if (window_data_.semantics_enabled) { + client_.UpdateSemantics(update->takeNodes()); + } } void RuntimeController::HandlePlatformMessage( fxl::RefPtr message) { - client_->HandlePlatformMessage(std::move(message)); -} - -void RuntimeController::DidCreateSecondaryIsolate(Dart_Isolate isolate) { - client_->DidCreateSecondaryIsolate(isolate); -} - -void RuntimeController::DidShutdownMainIsolate() { - client_->DidShutdownMainIsolate(); + client_.HandlePlatformMessage(std::move(message)); } Dart_Port RuntimeController::GetMainPort() { - if (!dart_controller_) { - return ILLEGAL_PORT; - } - if (!dart_controller_->dart_state()) { - return ILLEGAL_PORT; - } - return dart_controller_->dart_state()->main_port(); + return root_isolate_ ? root_isolate_->main_port() : ILLEGAL_PORT; } std::string RuntimeController::GetIsolateName() { - if (!dart_controller_) { - return ""; - } - if (!dart_controller_->dart_state()) { - return ""; - } - return dart_controller_->dart_state()->debug_name(); + return root_isolate_ ? root_isolate_->debug_name() : ""; } bool RuntimeController::HasLivePorts() { - if (!dart_controller_) { - return false; - } - UIDartState* dart_state = dart_controller_->dart_state(); - if (!dart_state) { + if (!root_isolate_) { return false; } - DartState::Scope scope(dart_state); + tonic::DartState::Scope scope(root_isolate_.get()); return Dart_HasLivePorts(); } tonic::DartErrorHandleType RuntimeController::GetLastError() { - 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(); + 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_; } } // namespace blink diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index 628bc699395c0e2e865c262525c833c6c835ba20..326c517f31db23249139253ec4ae778eba9fb24a 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -7,71 +7,108 @@ #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 : public WindowClient, public IsolateClient { +class RuntimeController final : public WindowClient { public: - static std::unique_ptr Create(RuntimeDelegate* client); + RuntimeController(RuntimeDelegate& client, + const DartVM* vm, + TaskRunners task_runners, + fml::WeakPtr resource_context, + fxl::RefPtr unref_queue); + ~RuntimeController(); - 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(); } + std::unique_ptr Clone() const; + + bool SetViewportMetrics(const ViewportMetrics& metrics); - void SetViewportMetrics(const ViewportMetrics& metrics); - void SetLocale(const std::string& language_code, + bool SetLocale(const std::string& language_code, const std::string& country_code); - void SetUserSettingsData(const std::string& data); - void SetSemanticsEnabled(bool enabled); - void BeginFrame(fxl::TimePoint frame_time); - void NotifyIdle(int64_t deadline); + bool SetUserSettingsData(const std::string& data); + + bool SetSemanticsEnabled(bool enabled); + + bool BeginFrame(fxl::TimePoint frame_time); + + bool NotifyIdle(int64_t deadline); - void DispatchPlatformMessage(fxl::RefPtr message); - void DispatchPointerDataPacket(const PointerDataPacket& packet); - void DispatchSemanticsAction(int32_t id, + bool DispatchPlatformMessage(fxl::RefPtr message); + + bool DispatchPointerDataPacket(const PointerDataPacket& packet); + + bool DispatchSemanticsAction(int32_t id, SemanticsAction action, std::vector args); Dart_Port GetMainPort(); + std::string GetIsolateName(); + bool HasLivePorts(); + tonic::DartErrorHandleType GetLastError(); - private: - explicit RuntimeController(RuntimeDelegate* client); + fml::WeakPtr GetRootIsolate(); - Window* GetWindow(); + std::pair GetRootIsolateReturnCode(); + 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; - void UpdateSemantics(SemanticsUpdate* update) override; - void HandlePlatformMessage(fxl::RefPtr message) override; - void DidCreateSecondaryIsolate(Dart_Isolate isolate) override; - void DidShutdownMainIsolate() override; + // |blink::WindowClient| + void UpdateSemantics(SemanticsUpdate* update) 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_; + // |blink::WindowClient| + void HandlePlatformMessage(fxl::RefPtr message) override; FXL_DISALLOW_COPY_AND_ASSIGN(RuntimeController); }; diff --git a/runtime/runtime_delegate.cc b/runtime/runtime_delegate.cc index 6ec55c4c2e6a017a3091e828b4d5a54119830d00..902672be06d8f959853ec06513bcdb86cf0d17d1 100644 --- a/runtime/runtime_delegate.cc +++ b/runtime/runtime_delegate.cc @@ -6,12 +6,6 @@ namespace blink { -RuntimeDelegate::~RuntimeDelegate() {} - -void RuntimeDelegate::DidCreateMainIsolate(Dart_Isolate isolate) {} - -void RuntimeDelegate::DidCreateSecondaryIsolate(Dart_Isolate isolate) {} - -void RuntimeDelegate::DidShutdownMainIsolate() {} +RuntimeDelegate::~RuntimeDelegate() = default; } // namespace blink diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index 36650fe7fb70b35117a26568afe747e60feb001b..c6d6c0a92b2b4e217c55cc66ab2c0b9c494fc0f7 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -18,14 +18,14 @@ 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(); + virtual void HandlePlatformMessage(fxl::RefPtr message) = 0; protected: virtual ~RuntimeDelegate(); diff --git a/runtime/runtime_init.cc b/runtime/runtime_init.cc deleted file mode 100644 index eda66e5495aed1b3e030f71ee0d4e6075fc335d2..0000000000000000000000000000000000000000 --- a/runtime/runtime_init.cc +++ /dev/null @@ -1,35 +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. - -#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 deleted file mode 100644 index 515ae284e34608c6d4dc559f522076dc5145db61..0000000000000000000000000000000000000000 --- a/runtime/runtime_init.h +++ /dev/null @@ -1,21 +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. - -#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 new file mode 100644 index 0000000000000000000000000000000000000000..030901e54269d921ffceca37952c1dbd4db5eac4 --- /dev/null +++ b/runtime/service_protocol.cc @@ -0,0 +1,279 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..056f7389ea79aba580877dca21fb5915752374b7 --- /dev/null +++ b/runtime/service_protocol.h @@ -0,0 +1,99 @@ +// 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 f9e25a3c8d6d7e22fb8a76be4b4eeb114916ba95..25edcfa23bd8579ecaf1c911f67a8d4cb1d1a80c 100644 --- a/shell/common/BUILD.gn +++ b/shell/common/BUILD.gn @@ -2,6 +2,8 @@ # 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) @@ -61,18 +63,18 @@ source_set("common") { "animator.h", "engine.cc", "engine.h", - "null_platform_view.cc", - "null_platform_view.h", - "null_rasterizer.cc", - "null_rasterizer.h", + "io_manager.cc", + "io_manager.h", + "isolate_configuration.cc", + "isolate_configuration.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", @@ -81,8 +83,8 @@ source_set("common") { "surface.h", "switches.cc", "switches.h", - "tracing_controller.cc", - "tracing_controller.h", + "thread_host.cc", + "thread_host.h", "vsync_waiter.cc", "vsync_waiter.h", "vsync_waiter_fallback.cc", @@ -90,8 +92,6 @@ 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,10 +99,13 @@ 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", @@ -112,7 +115,23 @@ source_set("common") { "//topaz/lib/tonic", ] - public_configs = [ - "$flutter_root:config", + 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", ] } diff --git a/shell/common/animator.cc b/shell/common/animator.cc index d5679a0160a86798177344481a2e058cbda13e39..60177a18f89aba89f07b9dbc7753f4288cf0aa3d 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -4,19 +4,18 @@ #include "flutter/shell/common/animator.h" -#include "flutter/common/threads.h" -#include "flutter/fml/trace_event.h" +#include "flutter/glue/trace_event.h" #include "lib/fxl/time/stopwatch.h" #include "third_party/dart/runtime/include/dart_tools_api.h" namespace shell { -Animator::Animator(fml::WeakPtr rasterizer, - VsyncWaiter* waiter, - Engine* engine) - : rasterizer_(rasterizer), - waiter_(waiter), - engine_(engine), +Animator::Animator(Delegate& delegate, + blink::TaskRunners task_runners, + std::unique_ptr waiter) + : delegate_(delegate), + task_runners_(std::move(task_runners)), + waiter_(std::move(waiter)), last_begin_frame_time_(), dart_frame_deadline_(0), layer_tree_pipeline_(fxl::MakeRefCounted(2)), @@ -79,7 +78,6 @@ 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; } @@ -94,13 +92,13 @@ void Animator::BeginFrame(fxl::TimePoint frame_start_time, { TRACE_EVENT2("flutter", "Framework Workload", "mode", "basic", "frame", FrameParity()); - engine_->BeginFrame(last_begin_frame_time_); + delegate_.OnAnimatorBeginFrame(*this, 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. - engine_->NotifyIdle(dart_frame_deadline_ + 100000); + delegate_.OnAnimatorNotifyIdle(*this, dart_frame_deadline_ + 100000); } } @@ -120,15 +118,7 @@ void Animator::Render(std::unique_ptr layer_tree) { // Commit the pending continuation. producer_continuation_.Complete(std::move(layer_tree)); - 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); - }); + delegate_.OnAnimatorDraw(*this, layer_tree_pipeline_); } bool Animator::CanReuseLastLayerTree() { @@ -137,10 +127,7 @@ bool Animator::CanReuseLastLayerTree() { void Animator::DrawLastLayerTree() { pending_frame_semaphore_.Signal(); - blink::Threads::Gpu()->PostTask([rasterizer = rasterizer_]() { - if (rasterizer.get()) - rasterizer->DrawLastLayerTree(); - }); + delegate_.OnAnimatorDrawLastLayerTree(*this); } void Animator::RequestFrame(bool regenerate_layer_tree) { @@ -164,31 +151,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. - 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(); - }); + 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(); + }); 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); + } + } + }); - engine_->NotifyIdle(dart_frame_deadline_); + delegate_.OnAnimatorNotifyIdle(*this, dart_frame_deadline_); } } // namespace shell diff --git a/shell/common/animator.h b/shell/common/animator.h index bc2ee21441b29eea3c2082c4d916e184df92f084..53b2ac68841589ac6c7b05398dd9ddccaf5d3e50 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/shell/common/engine.h" +#include "flutter/common/task_runners.h" #include "flutter/shell/common/rasterizer.h" #include "flutter/shell/common/vsync_waiter.h" #include "flutter/synchronization/pipeline.h" @@ -16,17 +16,28 @@ namespace shell { -class Animator { +class Animator final { public: - Animator(fml::WeakPtr rasterizer, - VsyncWaiter* waiter, - Engine* engine); + class Delegate { + public: + virtual void OnAnimatorBeginFrame(const Animator& animator, + fxl::TimePoint frame_time) = 0; - ~Animator(); + 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; + }; - void set_rasterizer(fml::WeakPtr rasterizer) { - rasterizer_ = rasterizer; - } + Animator(Delegate& delegate, + blink::TaskRunners task_runners, + std::unique_ptr waiter); + + ~Animator(); void RequestFrame(bool regenerate_layer_tree = true); @@ -51,9 +62,9 @@ class Animator { const char* FrameParity(); - fml::WeakPtr rasterizer_; - VsyncWaiter* waiter_; - Engine* engine_; + Delegate& delegate_; + blink::TaskRunners task_runners_; + std::unique_ptr waiter_; fxl::TimePoint last_begin_frame_time_; int64_t dart_frame_deadline_; @@ -67,7 +78,7 @@ class Animator { bool dimension_change_pending_; SkISize last_layer_tree_size_; - fml::WeakPtrFactory weak_factory_; + fxl::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(Animator); }; diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 3629b729c29f7438e49ca8264c24ec5a84889e4a..3d6fd496d3fa9fe092f189c29b30e97ab8b04d36 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -4,47 +4,20 @@ #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/dart_controller.h" -#include "flutter/runtime/dart_init.h" -#include "flutter/runtime/runtime_init.h" +#include "flutter/runtime/platform_impl.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" @@ -55,380 +28,208 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPictureRecorder.h" -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 - -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; +#ifdef ERROR +#undef ERROR #endif -} - -bool PathExists(const std::string& path) { - return access(path.c_str(), R_OK) == 0; -} - -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; -} -std::string GetScriptUriFromPath(const std::string& path) { - return "file://" + SanitizePath(path); -} - -} // namespace +namespace shell { -Engine::Engine(PlatformView* platform_view) - : platform_view_(platform_view->GetWeakPtr()), - animator_(std::make_unique( - platform_view->rasterizer().GetWeakRasterizerPtr(), - platform_view->GetVsyncWaiter(), - this)), +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), - user_settings_data_("{}"), activity_running_(false), have_surface_(false), - weak_factory_(this) {} + weak_factory_(this) { + weak_prototype_ = weak_factory_.GetWeakPtr(); -Engine::~Engine() {} + 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()); + } -void Engine::set_rasterizer(fml::WeakPtr rasterizer) { - animator_->set_rasterizer(rasterizer); + // 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 + ); } -fml::WeakPtr Engine::GetWeakPtr() { - return weak_factory_.GetWeakPtr(); +Engine::~Engine() { + if (legacy_sky_platform_) { + blink::ShutdownEngine(/* legacy_sky_platform_ */); + } } -#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; +fml::WeakPtr Engine::GetWeakPtr() const { + return weak_prototype_; +} + +bool Engine::UpdateAssetManager( + fxl::RefPtr new_asset_manager) { + if (asset_manager_ == new_asset_manager) { + return false; } -#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); + asset_manager_ = new_asset_manager; - if (file_handle_ == INVALID_HANDLE_VALUE) { - return; + if (!asset_manager_) { + return false; } - size_ = GetFileSize(file_handle_, nullptr); - if (size_ == INVALID_FILE_SIZE) { - size_ = 0; - 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()); + } } - int mapping_flags = executable ? PAGE_EXECUTE_READ : PAGE_READONLY; - mapping_handle_ = CreateFileMapping(file_handle_, nullptr, mapping_flags, 0, - size_, nullptr); - - CloseHandle(file_handle_); + return true; +} - if (mapping_handle_ == INVALID_HANDLE_VALUE) { - return; +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)); +} - int access_flags = FILE_MAP_READ; - if (executable) { - access_flags |= FILE_MAP_EXECUTE; +bool Engine::Run(RunConfiguration configuration) { + if (!configuration.IsValid()) { + FXL_LOG(ERROR) << "Engine run configuration was invalid."; + return false; } - auto mapping = MapViewOfFile(mapping_handle_, access_flags, 0, 0, size_); - if (mapping == INVALID_HANDLE_VALUE) { - CloseHandle(mapping_handle_); - mapping_handle_ = INVALID_HANDLE_VALUE; - return; + if (!PrepareAndLaunchIsolate(std::move(configuration))) { + return false; } - 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; + auto isolate = runtime_controller_->GetRootIsolate(); - fxl::UniqueFD fd(HANDLE_EINTR(open(asset_path.c_str(), O_RDONLY))); - if (fd.get() == -1) { - return nullptr; - } + bool isolate_running = + isolate && isolate->GetPhase() == blink::DartIsolate::Phase::Running; - int mmap_flags = PROT_READ; - if (executable) - mmap_flags |= PROT_EXEC; + if (isolate_running) { + tonic::DartState::Scope scope(isolate.get()); - 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 + if (settings_.root_isolate_create_callback) { + settings_.root_isolate_create_callback(); + } -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; + if (settings_.root_isolate_shutdown_callback) { + isolate->AddIsolateShutdownCallback( + settings_.root_isolate_shutdown_callback); + } + + // 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_); + } } - 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); } -#else -#error Unknown OS -#endif - blink::InitRuntime(vm_snapshot_data, vm_snapshot_instr, - default_isolate_snapshot_data, - default_isolate_snapshot_instr, bundle_path); + + return isolate_running; } -const std::string Engine::main_entrypoint_ = "main"; +bool Engine::PrepareAndLaunchIsolate(RunConfiguration configuration) { + TRACE_EVENT0("flutter", "Engine::PrepareAndLaunchIsolate"); -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); -} + UpdateAssetManager(configuration.GetAssetManager()); -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); + auto isolate_configuration = configuration.TakeIsolateConfiguration(); + + auto isolate = runtime_controller_->GetRootIsolate(); + + if (!isolate_configuration->PrepareIsolate(isolate)) { + FXL_DLOG(ERROR) << "Could not prepare to 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); + if (!isolate->Run(configuration.GetEntrypoint())) { + FXL_DLOG(ERROR) << "Could not run the isolate."; + return false; } + + return true; } void Engine::BeginFrame(fxl::TimePoint frame_time) { TRACE_EVENT0("flutter", "Engine::BeginFrame"); - if (runtime_) - runtime_->BeginFrame(frame_time); + runtime_controller_->BeginFrame(frame_time); } void Engine::NotifyIdle(int64_t deadline) { TRACE_EVENT0("flutter", "Engine::NotifyIdle"); - 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); + runtime_controller_->NotifyIdle(deadline); } -void Engine::SetAssetBundlePath(const std::string& bundle_path) { - TRACE_EVENT0("flutter", "Engine::SetAssetBundlePath"); - ConfigureAssetBundle(bundle_path); +std::pair Engine::GetUIIsolateReturnCode() { + return runtime_controller_->GetRootIsolateReturnCode(); } Dart_Port Engine::GetUIIsolateMainPort() { - if (!runtime_) - return ILLEGAL_PORT; - return runtime_->GetMainPort(); + return runtime_controller_->GetMainPort(); } std::string Engine::GetUIIsolateName() { - if (!runtime_) { - return ""; - } - return runtime_->GetIsolateName(); + return runtime_controller_->GetIsolateName(); } bool Engine::UIIsolateHasLivePorts() { - if (!runtime_) - return false; - return runtime_->HasLivePorts(); + return runtime_controller_->HasLivePorts(); } tonic::DartErrorHandleType Engine::GetUIIsolateLastError() { - if (!runtime_) - return tonic::kNoError; - return runtime_->GetLastError(); + return runtime_controller_->GetLastError(); } tonic::DartErrorHandleType Engine::GetLoadScriptError() { return load_script_error_; } -void Engine::OnOutputSurfaceCreated(const fxl::Closure& gpu_continuation) { - blink::Threads::Gpu()->PostTask(gpu_continuation); +void Engine::OnOutputSurfaceCreated() { have_surface_ = true; StartAnimatorIfPossible(); - if (runtime_) - ScheduleFrame(); + ScheduleFrame(); } -void Engine::OnOutputSurfaceDestroyed(const fxl::Closure& gpu_continuation) { +void Engine::OnOutputSurfaceDestroyed() { have_surface_ = false; StopAnimator(); - blink::Threads::Gpu()->PostTask(gpu_continuation); } void Engine::SetViewportMetrics(const blink::ViewportMetrics& metrics) { @@ -436,8 +237,7 @@ void Engine::SetViewportMetrics(const blink::ViewportMetrics& metrics) { viewport_metrics_.physical_height != metrics.physical_height || viewport_metrics_.physical_width != metrics.physical_width; viewport_metrics_ = metrics; - if (runtime_) - runtime_->SetViewportMetrics(viewport_metrics_); + runtime_controller_->SetViewportMetrics(viewport_metrics_); if (animator_) { if (dimensions_changed) animator_->SetDimensionChangePending(); @@ -459,8 +259,7 @@ void Engine::DispatchPlatformMessage( return; } - if (runtime_) { - runtime_->DispatchPlatformMessage(std::move(message)); + if (runtime_controller_->DispatchPlatformMessage(std::move(message))) { return; } @@ -493,7 +292,6 @@ bool Engine::HandleLifecyclePlatformMessage(blink::PlatformMessage* message) { bool Engine::HandleNavigationPlatformMessage( fxl::RefPtr message) { - FXL_DCHECK(!runtime_); const auto& data = message->data(); rapidjson::Document document; @@ -532,99 +330,33 @@ bool Engine::HandleLocalizationPlatformMessage( if (!language.IsString() || !country.IsString()) return false; - language_code_ = language.GetString(); - country_code_ = country.GetString(); - if (runtime_) - runtime_->SetLocale(language_code_, country_code_); - return true; + return runtime_controller_->SetLocale(language.GetString(), + country.GetString()); } void Engine::HandleSettingsPlatformMessage(blink::PlatformMessage* message) { const auto& data = message->data(); std::string jsonData(reinterpret_cast(data.data()), data.size()); - user_settings_data_ = jsonData; - if (runtime_) { - runtime_->SetUserSettingsData(user_settings_data_); - if (have_surface_) - ScheduleFrame(); + if (runtime_controller_->SetUserSettingsData(std::move(jsonData)) && + have_surface_) { + ScheduleFrame(); } } -void Engine::DispatchPointerDataPacket(const PointerDataPacket& packet) { - if (runtime_) - runtime_->DispatchPointerDataPacket(packet); +void Engine::DispatchPointerDataPacket(const blink::PointerDataPacket& packet) { + runtime_controller_->DispatchPointerDataPacket(packet); } void Engine::DispatchSemanticsAction(int id, blink::SemanticsAction action, std::vector args) { - if (runtime_) - runtime_->DispatchSemanticsAction(id, action, std::move(args)); + runtime_controller_->DispatchSemanticsAction(id, action, std::move(args)); } void Engine::SetSemanticsEnabled(bool 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_); - } - } + runtime_controller_->SetSemanticsEnabled(enabled); } -void Engine::DidCreateSecondaryIsolate(Dart_Isolate isolate) {} - void Engine::StopAnimator() { animator_->Stop(); } @@ -659,49 +391,34 @@ void Engine::Render(std::unique_ptr layer_tree) { } void Engine::UpdateSemantics(blink::SemanticsNodeUpdates 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)); - })); + delegate_.OnEngineUpdateSemantics(*this, std::move(update)); } void Engine::HandlePlatformMessage( fxl::RefPtr message) { if (message->channel() == kAssetChannel) { HandleAssetPlatformMessage(std::move(message)); - return; + } else { + delegate_.OnEngineHandlePlatformMessage(*this, std::move(message)); } - 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 (GetAssetAsBuffer(asset_name, &asset_data)) { + if (asset_manager_ && asset_manager_->GetAsBuffer(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 a0c5183338a434f5c1522bf7c051c3f216371f28..ede442ee3e8a43763c32ca0e9376ac7b42b50602 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -5,131 +5,144 @@ #ifndef SHELL_COMMON_ENGINE_H_ #define SHELL_COMMON_ENGINE_H_ -#include "flutter/assets/zip_asset_store.h" -#include "flutter/assets/asset_provider.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/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 : public blink::RuntimeDelegate { +class Engine final : public blink::RuntimeDelegate { public: - explicit Engine(PlatformView* platform_view); + 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); ~Engine() override; - fml::WeakPtr GetWeakPtr(); - - static void Init(const std::string& bundle_path); + fml::WeakPtr GetWeakPtr() const; - void RunBundle(const std::string& bundle_path, - const std::string& entrypoint = main_entrypoint_, - bool reuse_runtime_controller = false); + FXL_WARN_UNUSED_RESULT + bool Run(RunConfiguration configuration); - // 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); + // 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); - // 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); + bool UpdateAssetManager(fxl::RefPtr asset_manager); void BeginFrame(fxl::TimePoint frame_time); - void NotifyIdle(int64_t deadline); - void RunFromSource(const std::string& main, - const std::string& packages, - const std::string& bundle); - void SetAssetBundlePath(const std::string& bundle_path); + void NotifyIdle(int64_t deadline); Dart_Port GetUIIsolateMainPort(); + std::string GetUIIsolateName(); + bool UIIsolateHasLivePorts(); + tonic::DartErrorHandleType GetUIIsolateLastError(); + tonic::DartErrorHandleType GetLoadScriptError(); - void OnOutputSurfaceCreated(const fxl::Closure& gpu_continuation); - void OnOutputSurfaceDestroyed(const fxl::Closure& gpu_continuation); + std::pair GetUIIsolateReturnCode(); + + void OnOutputSurfaceCreated(); + + void OnOutputSurfaceDestroyed(); + void SetViewportMetrics(const blink::ViewportMetrics& metrics); + void DispatchPlatformMessage(fxl::RefPtr message); - void DispatchPointerDataPacket(const PointerDataPacket& packet); + + void DispatchPointerDataPacket(const blink::PointerDataPacket& packet); + void DispatchSemanticsAction(int id, blink::SemanticsAction action, std::vector args); + void SetSemanticsEnabled(bool enabled); - void ScheduleFrame(bool regenerate_layer_tree = true) override; - void set_rasterizer(fml::WeakPtr rasterizer); + void ScheduleFrame(bool regenerate_layer_tree = true) override; private: - // RuntimeDelegate methods: + 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_; + + // |blink::RuntimeDelegate| 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(); - - 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); + void StartAnimatorIfPossible(); 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); - static const std::string main_entrypoint_; + bool GetAssetAsBuffer(const std::string& name, std::vector* data); - 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_; + bool PrepareAndLaunchIsolate(RunConfiguration configuration); FXL_DISALLOW_COPY_AND_ASSIGN(Engine); }; diff --git a/shell/common/io_manager.cc b/shell/common/io_manager.cc new file mode 100644 index 0000000000000000000000000000000000000000..4161422978fcf1c80e6c11a1cf0022a3580d15cf --- /dev/null +++ b/shell/common/io_manager.cc @@ -0,0 +1,73 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..1077a28d0ae362fa866be690cb16dec257f4dd8c --- /dev/null +++ b/shell/common/io_manager.h @@ -0,0 +1,52 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..3c634022a348f0bb2a2c1ce543f088a91a47c32f --- /dev/null +++ b/shell/common/isolate_configuration.cc @@ -0,0 +1,148 @@ +// 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" + +#ifdef ERROR +#undef ERROR +#endif + +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 new file mode 100644 index 0000000000000000000000000000000000000000..82d06dac621b26ae56181488d7d454d876d5c070 --- /dev/null +++ b/shell/common/isolate_configuration.h @@ -0,0 +1,51 @@ +// 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 deleted file mode 100644 index 49fdf5a935b80e7e82a085c49ec7e0145ebc2381..0000000000000000000000000000000000000000 --- a/shell/common/null_platform_view.cc +++ /dev/null @@ -1,37 +0,0 @@ -// 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 deleted file mode 100644 index eb23d67b48a7c554817152e5e31a2dc4e2460aa7..0000000000000000000000000000000000000000 --- a/shell/common/null_platform_view.h +++ /dev/null @@ -1,39 +0,0 @@ -// 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 deleted file mode 100644 index 81efdd11d4970fbccf85dde25f58935073b1bb3b..0000000000000000000000000000000000000000 --- a/shell/common/null_rasterizer.cc +++ /dev/null @@ -1,67 +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. - -#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 deleted file mode 100644 index 8558a3c3accaa5e1fc7adc9e7dca0e0100078d28..0000000000000000000000000000000000000000 --- a/shell/common/null_rasterizer.h +++ /dev/null @@ -1,51 +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. - -#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 2d5715a1733bdc9ec7d1fe84f907a86e784a307e..b2bfce051a5bf5067a3ec918818a58bb27477a33 100644 --- a/shell/common/platform_view.cc +++ b/shell/common/platform_view.cc @@ -6,124 +6,74 @@ #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(std::unique_ptr rasterizer) - : rasterizer_(std::move(rasterizer)), size_(SkISize::Make(0, 0)) { - rasterizer_->SetTextureRegistry(&texture_registry_); - Shell::Shared().AddPlatformView(this); +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() { - Shell::Shared().RemovePlatformView(this); +PlatformView::~PlatformView() = default; - Rasterizer* rasterizer = rasterizer_.release(); - blink::Threads::Gpu()->PostTask([rasterizer]() { delete rasterizer; }); - - Engine* engine = engine_.release(); - blink::Threads::UI()->PostTask([engine]() { delete engine; }); -} - -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::CreateEngine() { - engine_.reset(new Engine(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_); } void PlatformView::DispatchPlatformMessage( fxl::RefPtr message) { - blink::Threads::UI()->PostTask( - [engine = engine_->GetWeakPtr(), message = std::move(message)] { - if (engine) { - engine->DispatchPlatformMessage(message); - } - }); + delegate_.OnPlatformViewDispatchPlatformMessage(*this, std::move(message)); +} + +void PlatformView::DispatchPointerDataPacket( + std::unique_ptr packet) { + delegate_.OnPlatformViewDispatchPointerDataPacket(*this, std::move(packet)); } void PlatformView::DispatchSemanticsAction(int32_t id, blink::SemanticsAction action, std::vector 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)); - } - }); + delegate_.OnPlatformViewDispatchSemanticsAction(*this, id, action, + std::move(args)); } void PlatformView::SetSemanticsEnabled(bool enabled) { - blink::Threads::UI()->PostTask([engine = engine_->GetWeakPtr(), enabled] { - if (engine) - engine->SetSemanticsEnabled(enabled); - }); + delegate_.OnPlatformViewSetSemanticsEnabled(*this, enabled); } -void PlatformView::NotifyCreated(std::unique_ptr surface) { - NotifyCreated(std::move(surface), []() {}); +void PlatformView::SetViewportMetrics(const blink::ViewportMetrics& metrics) { + delegate_.OnPlatformViewSetViewportMetrics(*this, metrics); } -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::NotifyCreated() { + delegate_.OnPlatformViewCreated(*this, CreateRenderingSurface()); } void PlatformView::NotifyDestroyed() { - fxl::AutoResetWaitableEvent latch; - - auto engine_continuation = [this, &latch]() { - rasterizer_->Teardown(&latch); - }; - - blink::Threads::UI()->PostTask([this, engine_continuation]() { - engine_->OnOutputSurfaceDestroyed(engine_continuation); - }); - - latch.Wait(); + delegate_.OnPlatformViewDestroyed(*this); } -std::weak_ptr PlatformView::GetWeakPtr() { - return shared_from_this(); +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; } -VsyncWaiter* PlatformView::GetVsyncWaiter() { - if (!vsync_waiter_) - vsync_waiter_ = std::make_unique(); - return vsync_waiter_.get(); +fml::WeakPtr PlatformView::GetWeakPtr() const { + return weak_prototype_; } void PlatformView::UpdateSemantics(blink::SemanticsNodeUpdates update) {} @@ -135,71 +85,31 @@ void PlatformView::HandlePlatformMessage( } void PlatformView::RegisterTexture(std::shared_ptr texture) { - ASSERT_IS_PLATFORM_THREAD - blink::Threads::Gpu()->PostTask([this, texture]() { - rasterizer_->GetTextureRegistry().RegisterTexture(texture); - }); + delegate_.OnPlatformViewRegisterTexture(*this, std::move(texture)); } void PlatformView::UnregisterTexture(int64_t texture_id) { - ASSERT_IS_PLATFORM_THREAD - blink::Threads::Gpu()->PostTask([this, texture_id]() { - rasterizer_->GetTextureRegistry().UnregisterTexture(texture_id); - }); + delegate_.OnPlatformViewUnregisterTexture(*this, texture_id); } void PlatformView::MarkTextureFrameAvailable(int64_t texture_id) { - ASSERT_IS_PLATFORM_THREAD - blink::Threads::UI()->PostTask([this]() { engine_->ScheduleFrame(false); }); + delegate_.OnPlatformViewMarkTextureFrameAvailable(*this, texture_id); } -void PlatformView::SetupResourceContextOnIOThread() { - fxl::AutoResetWaitableEvent latch; - - blink::Threads::IO()->PostTask( - [this, &latch]() { SetupResourceContextOnIOThreadPerform(&latch); }); - - latch.Wait(); +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::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(); +void PlatformView::SetNextFrameCallback(fxl::Closure closure) { + if (!closure) { return; } - 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(); + delegate_.OnPlatformViewSetNextFrameCallback(*this, std::move(closure)); } } // namespace shell diff --git a/shell/common/platform_view.h b/shell/common/platform_view.h index 66b1fcae10c7939e8a12bff974ee8c08043d4021..56179a61147773d984a12096c434e825b36f830e 100644 --- a/shell/common/platform_view.h +++ b/shell/common/platform_view.h @@ -7,63 +7,104 @@ #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/shell/common/engine.h" -#include "flutter/shell/common/shell.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/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 Rasterizer; +class Shell; -class PlatformView : public std::enable_shared_from_this { +class PlatformView { public: - 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; + 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; }; - void SetupResourceContextOnIOThread(); + explicit PlatformView(Delegate& delegate, blink::TaskRunners task_runners); virtual ~PlatformView(); - virtual void Attach() = 0; + virtual std::unique_ptr CreateVSyncWaiter(); void DispatchPlatformMessage(fxl::RefPtr message); + void DispatchSemanticsAction(int32_t id, blink::SemanticsAction action, std::vector args); - void SetSemanticsEnabled(bool enabled); - void NotifyCreated(std::unique_ptr surface); + virtual void SetSemanticsEnabled(bool enabled); - void NotifyCreated(std::unique_ptr surface, - fxl::Closure continuation); + void SetViewportMetrics(const blink::ViewportMetrics& metrics); - void NotifyDestroyed(); + void NotifyCreated(); - std::weak_ptr GetWeakPtr(); + virtual void NotifyDestroyed(); - // The VsyncWaiter will live at least as long as the PlatformView. - virtual VsyncWaiter* GetVsyncWaiter(); + // Unlike all other methods on the platform view, this one may be called on a + // non-platform task runner. + virtual sk_sp CreateResourceContext() const; - virtual bool ResourceContextMakeCurrent() = 0; + fml::WeakPtr GetWeakPtr() const; 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); @@ -71,34 +112,18 @@ class PlatformView : public std::enable_shared_from_this { void UnregisterTexture(int64_t texture_id); // Called once per texture update (e.g. video frame), on the platform thread. - 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; + void MarkTextureFrameAvailable(int64_t texture_id); protected: - 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_; + PlatformView::Delegate& delegate_; + const blink::TaskRunners task_runners_; 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 deleted file mode 100644 index 8785c4812e202c933b449cc35843e07d05aac158..0000000000000000000000000000000000000000 --- a/shell/common/platform_view_service_protocol.cc +++ /dev/null @@ -1,447 +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. - -#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 deleted file mode 100644 index b7f74b56a08ba7f0aaddda8fe6ab24d5d4b258b6..0000000000000000000000000000000000000000 --- a/shell/common/platform_view_service_protocol.h +++ /dev/null @@ -1,85 +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. - -#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 905ee6285c5d377c0ff5da3a43de1ddcb0330458..5a519b3efea26d2fb337a0be82071955f1311511 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -4,8 +4,205 @@ #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 6f45f49d8178aad2123f81af6573e56218c011f7..908717b74c168a869936cb208bc07353e4aa286e 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -7,6 +7,7 @@ #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" @@ -16,34 +17,64 @@ namespace shell { -class Rasterizer { +class Rasterizer final { public: - virtual ~Rasterizer(); + Rasterizer(blink::TaskRunners task_runners); - virtual void Setup(std::unique_ptr surface_or_null, - fxl::Closure rasterizer_continuation, - fxl::AutoResetWaitableEvent* setup_completion_event) = 0; + ~Rasterizer(); - virtual void Teardown( - fxl::AutoResetWaitableEvent* teardown_completion_event) = 0; + void Setup(std::unique_ptr surface); - virtual void Clear(SkColor color, const SkISize& size) = 0; + void Teardown(); - virtual fml::WeakPtr GetWeakRasterizerPtr() = 0; + fml::WeakPtr GetWeakPtr() const; - virtual flow::LayerTree* GetLastLayerTree() = 0; + flow::LayerTree* GetLastLayerTree(); - virtual void DrawLastLayerTree() = 0; + void DrawLastLayerTree(); - virtual flow::TextureRegistry& GetTextureRegistry() = 0; + flow::TextureRegistry* GetTextureRegistry(); - virtual void Draw( - fxl::RefPtr> pipeline) = 0; + void Draw(fxl::RefPtr> pipeline); - // Set a callback to be called once when the next frame is drawn. - virtual void AddNextFrameCallback(fxl::Closure nextFrameCallback) = 0; + enum class ScreenshotType { + SkiaPicture, + UncompressedImage, // In kN32_SkColorType format + CompressedImage, + }; - virtual void SetTextureRegistry(flow::TextureRegistry* textureRegistry) = 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); }; } // namespace shell diff --git a/shell/common/run_configuration.cc b/shell/common/run_configuration.cc new file mode 100644 index 0000000000000000000000000000000000000000..7fb385fb4d9dc351f4e51fb15fdaaa6294f8365d --- /dev/null +++ b/shell/common/run_configuration.cc @@ -0,0 +1,80 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..59aa07566685cf2914d14955d0180b9c72ceb198 --- /dev/null +++ b/shell/common/run_configuration.h @@ -0,0 +1,56 @@ +// 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 14f8fee84bb5f75bd8518229dd0b726b7e0b7976..6bb051460eaefcc0512bf1913b14deaca4d794b6 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -2,362 +2,863 @@ // 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/common/settings.h" -#include "flutter/common/threads.h" +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/fml/file.h" #include "flutter/fml/icu_util.h" #include "flutter/fml/message_loop.h" -#include "flutter/fml/trace_event.h" -#include "flutter/runtime/dart_init.h" +#include "flutter/glue/trace_event.h" +#include "flutter/runtime/dart_vm.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" +#ifdef ERROR +#undef ERROR +#endif + namespace shell { -namespace { -static Shell* g_shell = nullptr; +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; + } -template -bool GetSwitchValue(const fxl::CommandLine& command_line, - Switch sw, - T* result) { - std::string switch_string; + 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; + } - if (!command_line.GetOptionValue(FlagForSwitch(sw), &switch_string)) { + 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); + } + + if (!settings_.skia_deterministic_rendering_on_cpu) { + SkGraphics::Init(); + } else { + FXL_DLOG(INFO) << "Skia deterministic rendering is enabled."; + } + + // 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_) { return false; } - std::stringstream stream(switch_string); - T value = 0; - if (stream >> value) { - *result = value; - return true; + if (!platform_view || !engine || !rasterizer || !io_manager) { + return false; } - 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); + } + + return true; } -} // namespace +const blink::Settings& Shell::GetSettings() const { + return settings_; +} -Shell::Shell(fxl::CommandLine command_line) - : command_line_(std::move(command_line)) { - FXL_DCHECK(!g_shell); +const blink::TaskRunners& Shell::GetTaskRunners() const { + return task_runners_; +} - 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::GetRasterizer() { + FXL_DCHECK(is_setup_); + return rasterizer_->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::GetEngine() { + FXL_DCHECK(is_setup_); + return engine_->GetWeakPtr(); +} - blink::Threads::Gpu()->PostTask([this]() { InitGpuThread(); }); - blink::Threads::UI()->PostTask([this]() { InitUIThread(); }); +fml::WeakPtr Shell::GetPlatformView() { + FXL_DCHECK(is_setup_); + return platform_view_->GetWeakPtr(); +} - blink::SetRegisterNativeServiceProtocolExtensionHook( - PlatformViewServiceProtocol::RegisterHook); +const blink::DartVM& Shell::GetDartVM() const { + return *vm_; } -Shell::~Shell() {} +// |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()); -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"); + // 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. - fml::icu::InitializeICU(icu_data_path); + 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(); + }); - if (!command_line.HasOption( - FlagForSwitch(Switch::SkiaDeterministicRendering))) - SkGraphics::Init(); + 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(); +} - blink::Settings settings; - settings.application_library_path = application_library_path; +// |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()); - // Enable Observatory - settings.enable_observatory = - !command_line.HasOption(FlagForSwitch(Switch::DisableObservatory)); + // 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. + + fxl::AutoResetWaitableEvent latch; - // 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; + auto gpu_task = [rasterizer = rasterizer_->GetWeakPtr(), &latch]() { + if (rasterizer) { + rasterizer->Teardown(); } - } + // 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(); +} - // Checked mode overrides. - settings.dart_non_checked_mode = - command_line.HasOption(FlagForSwitch(Switch::DartNonCheckedMode)); +// |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); + } + }); +} - settings.ipv6 = command_line.HasOption(FlagForSwitch(Switch::IPv6)); +// |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)); + } + }); +} - settings.start_paused = - command_line.HasOption(FlagForSwitch(Switch::StartPaused)); +// |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); + } + })); +} - settings.enable_dart_profiling = - command_line.HasOption(FlagForSwitch(Switch::EnableDartProfiling)); +// |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.enable_software_rendering = - command_line.HasOption(FlagForSwitch(Switch::EnableSoftwareRendering)); +// |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.using_blink = - command_line.HasOption(FlagForSwitch(Switch::EnableBlink)); +// |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.endless_trace_buffer = - command_line.HasOption(FlagForSwitch(Switch::EndlessTraceBuffer)); +// |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.trace_startup = - command_line.HasOption(FlagForSwitch(Switch::TraceStartup)); +// |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()); - command_line.GetOptionValue(FlagForSwitch(Switch::AotSnapshotPath), - &settings.aot_snapshot_path); + // 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(); - command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotData), - &settings.aot_vm_snapshot_data_filename); + if (!registry) { + return; + } - command_line.GetOptionValue(FlagForSwitch(Switch::AotVmSnapshotInstructions), - &settings.aot_vm_snapshot_instr_filename); + auto texture = registry->GetTexture(texture_id); - command_line.GetOptionValue(FlagForSwitch(Switch::AotIsolateSnapshotData), - &settings.aot_isolate_snapshot_data_filename); + if (!texture) { + return; + } - command_line.GetOptionValue(FlagForSwitch(Switch::AotSharedLibraryPath), - &settings.aot_shared_library_path); + texture->MarkNewFrameAvailable(); + }); - command_line.GetOptionValue( - FlagForSwitch(Switch::AotIsolateSnapshotInstructions), - &settings.aot_isolate_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::CacheDirPath), - &settings.temp_directory_path); +// |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)); + } + }); +} - settings.use_test_fonts = - command_line.HasOption(FlagForSwitch(Switch::UseTestFonts)); +// |shell::Animator::Delegate| +void Shell::OnAnimatorBeginFrame(const Animator& animator, + fxl::TimePoint frame_time) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - 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 (engine_) { + engine_->BeginFrame(frame_time); } +} - command_line.GetOptionValue(FlagForSwitch(Switch::LogTag), &settings.log_tag); +// |shell::Animator::Delegate| +void Shell::OnAnimatorNotifyIdle(const Animator& animator, int64_t deadline) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - blink::Settings::Set(settings); + if (engine_) { + engine_->NotifyIdle(deadline); + } +} - Init(std::move(command_line), bundle_path); +// |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); + } + }); } -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 +// |shell::Animator::Delegate| +void Shell::OnAnimatorDrawLastLayerTree(const Animator& animator) { + FXL_DCHECK(is_setup_); - FXL_DCHECK(!g_shell); - g_shell = new Shell(std::move(command_line)); - blink::Threads::UI()->PostTask( - [bundle_path]() { Engine::Init(bundle_path); }); + task_runners_.GetGPUTaskRunner()->PostTask( + [rasterizer = rasterizer_->GetWeakPtr()]() { + if (rasterizer) { + rasterizer->DrawLastLayerTree(); + } + }); } -Shell& Shell::Shared() { - FXL_DCHECK(g_shell); - return *g_shell; +// |shell::Engine::Delegate| +void Shell::OnEngineUpdateSemantics(const Engine& engine, + blink::SemanticsNodeUpdates update) { + FXL_DCHECK(is_setup_); + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); + + task_runners_.GetPlatformTaskRunner()->PostTask( + [view = platform_view_->GetWeakPtr(), update = std::move(update)] { + if (view) { + view->UpdateSemantics(std::move(update)); + } + }); } -const fxl::CommandLine& Shell::GetCommandLine() const { - return command_line_; +// |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)); + } + }); } -void Shell::InitGpuThread() { - gpu_thread_checker_.reset(new fxl::ThreadChecker()); +// |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(); } -void Shell::InitUIThread() { - ui_thread_checker_.reset(new fxl::ThreadChecker()); +// |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::AddPlatformView(PlatformView* platform_view) { - if (platform_view == nullptr) { - return; +// |blink::ServiceProtocol::Handler| +blink::ServiceProtocol::Handler::Description +Shell::GetServiceProtocolDescription() const { + return { + engine_->GetUIIsolateMainPort(), + engine_->GetUIIsolateName(), + }; +} + +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); } - std::lock_guard lock(platform_views_mutex_); - platform_views_.insert(platform_view); } -void Shell::RemovePlatformView(PlatformView* platform_view) { - if (platform_view == nullptr) { - return; +// 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; } - std::lock_guard lock(platform_views_mutex_); - platform_views_.erase(platform_view); + ServiceProtocolParameterError(response, + "Could not capture image screenshot."); + return false; } -void Shell::IteratePlatformViews( - std::function iterator) const { - if (iterator == nullptr) { - return; +// 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; } - std::lock_guard lock(platform_views_mutex_); - for (PlatformView* view : platform_views_) { - if (!iterator(view)) { - 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; + } + + FXL_DCHECK(false); + return false; } -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::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::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; - }); +// Service protocol handler +bool Shell::OnServiceProtocolSetAssetBundlePath( + const blink::ServiceProtocol::Handler::ServiceProtocolMap& params, + rapidjson::Document& response) { + FXL_DCHECK(task_runners_.GetUITaskRunner()->RunsTasksOnCurrentThread()); - latch->Signal(); -} + if (params.count("assetDirectory") == 0) { + ServiceProtocolParameterError(response, + "'assetDirectory' parameter is missing."); + return false; + } -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; - 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(); + 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; + } + + FXL_DCHECK(false); + return false; } -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; +Rasterizer::Screenshot Shell::Screenshot( + Rasterizer::ScreenshotType screenshot_type, + bool base64_encode) { + TRACE_EVENT0("flutter", "Shell::Screenshot"); + 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); } - *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.Signal(); }); - - latch->Signal(); + latch.Wait(); + return screenshot; } } // namespace shell diff --git a/shell/common/shell.h b/shell/common/shell.h index 92c315dcf2aa79a2df4e7ea1b5152c695fcb84a9..02a642b0ba40f1f6c8de15c17972979ab6b3e903 100644 --- a/shell/common/shell.h +++ b/shell/common/shell.h @@ -5,96 +5,214 @@ #ifndef SHELL_COMMON_SHELL_H_ #define SHELL_COMMON_SHELL_H_ -#include -#include - +#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 "flutter/fml/thread.h" -#include "flutter/shell/common/tracing_controller.h" -#include "lib/fxl/command_line.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 "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 PlatformView; - -class 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); + ~Shell(); - static void InitStandalone(fxl::CommandLine command_line, - std::string icu_data_path = "", - std::string application_library_path = "", - std::string bundle_path = ""); + const blink::Settings& GetSettings() const; - static Shell& Shared(); + const blink::TaskRunners& GetTaskRunners() const; - const fxl::CommandLine& GetCommandLine() const; + fml::WeakPtr GetRasterizer(); - void AddPlatformView(PlatformView* platform_view); + fml::WeakPtr GetEngine(); - void RemovePlatformView(PlatformView* platform_view); + fml::WeakPtr GetPlatformView(); - void IteratePlatformViews( - std::function iterator) const; + const blink::DartVM& GetDartVM() 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); + bool IsSetup() const; - void SetAssetBundlePathInPlatformView(uintptr_t view_id, - 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); private: - 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); + 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_DISALLOW_COPY_AND_ASSIGN(Shell); }; diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc new file mode 100644 index 0000000000000000000000000000000000000000..67689341a15862ce86f0cca545f13c8cb5e0f443 --- /dev/null +++ b/shell/common/shell_unittests.cc @@ -0,0 +1,133 @@ +// 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 01d288a5e50852b8b76948426cc22f4be7a5205d..228647e8b3512f405c9880b7afaf3ff1ec6c64f6 100644 --- a/shell/common/surface.cc +++ b/shell/common/surface.cc @@ -3,6 +3,7 @@ // 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" @@ -59,27 +60,22 @@ bool SurfaceFrame::PerformSubmit() { return false; } -Surface::Surface() : scale_(1.0) {} - -Surface::~Surface() = default; +Surface::Surface() : Surface(std::make_unique()) {} -bool Surface::SupportsScaling() const { - return false; +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(); } -double Surface::GetScale() const { - return scale_; +Surface::~Surface() { + compositor_context_->OnGrContextDestroyed(); } -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; +flow::CompositorContext& Surface::GetCompositorContext() { + return *compositor_context_; } } // namespace shell diff --git a/shell/common/surface.h b/shell/common/surface.h index 906480237f416eb19d8226b0f406fd2776bbf842..6133a7d519fffbf5a6b296c76812f9aa88bee6c8 100644 --- a/shell/common/surface.h +++ b/shell/common/surface.h @@ -7,7 +7,7 @@ #include -#include "lib/fxl/compiler_specific.h" +#include "flutter/flow/compositor_context.h" #include "lib/fxl/macros.h" #include "third_party/skia/include/core/SkCanvas.h" @@ -45,6 +45,8 @@ class Surface { public: Surface(); + Surface(std::unique_ptr compositor_context); + virtual ~Surface(); virtual bool IsValid() = 0; @@ -53,14 +55,12 @@ class Surface { virtual GrContext* GetContext() = 0; - virtual bool SupportsScaling() const; - - double GetScale() const; - - void SetScale(double scale); + flow::CompositorContext& GetCompositorContext(); private: - double scale_; + std::unique_ptr compositor_context_; + + FXL_DISALLOW_COPY_AND_ASSIGN(Surface); }; } // namespace shell diff --git a/shell/common/switches.cc b/shell/common/switches.cc index c1c82ff166ac190895aa611b1ce532f84c3b1426..82da6ee180af88a000ab02aea7184069af8f9b8f 100644 --- a/shell/common/switches.cc +++ b/shell/common/switches.cc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -90,4 +91,125 @@ 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 91778a78e92cc6b0b8e627d721f582b6b2bd247a..6b67b1f6a156761cb99660d5f95bc8243510f99c 100644 --- a/shell/common/switches.h +++ b/shell/common/switches.h @@ -2,6 +2,8 @@ // 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_ @@ -23,12 +25,29 @@ 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 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(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(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 " @@ -73,10 +92,6 @@ 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, @@ -113,7 +128,9 @@ DEF_SWITCHES_END void PrintUsage(const std::string& executable_name); -const fxl::StringView FlagForSwitch(Switch sw); +const fxl::StringView FlagForSwitch(Switch swtch); + +blink::Settings SettingsFromCommandLine(const fxl::CommandLine& command_line); } // namespace shell diff --git a/shell/common/thread_host.cc b/shell/common/thread_host.cc new file mode 100644 index 0000000000000000000000000000000000000000..f35594829d5d95e8c9e5922b973b91e10e835ab6 --- /dev/null +++ b/shell/common/thread_host.cc @@ -0,0 +1,38 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..a688aa6a06a85bbfd218b81ff57dc7d284767c50 --- /dev/null +++ b/shell/common/thread_host.h @@ -0,0 +1,43 @@ +// 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 deleted file mode 100644 index 6fa8d9d5ee87fe54d6bf639e4cf917cf38ec8158..0000000000000000000000000000000000000000 --- a/shell/common/tracing_controller.cc +++ /dev/null @@ -1,51 +0,0 @@ -// 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 deleted file mode 100644 index 3f9e6f03ab14ca91485df03f396154df8ee01d0e..0000000000000000000000000000000000000000 --- a/shell/common/tracing_controller.h +++ /dev/null @@ -1,34 +0,0 @@ -// 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 5acc235b1f68d99635e0a4641bccacdc8381fb79..ba2f21c389c11e1828500ea04f086f261718ad55 100644 --- a/shell/common/vsync_waiter.cc +++ b/shell/common/vsync_waiter.cc @@ -4,8 +4,45 @@ #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 77319ed8b69669c052e8521264ccf6b84dde1956..82231fdf4f8533c54d75845f130181a5cecc561e 100644 --- a/shell/common/vsync_waiter.h +++ b/shell/common/vsync_waiter.h @@ -6,7 +6,10 @@ #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 { @@ -16,9 +19,23 @@ class VsyncWaiter { using Callback = std::function; - virtual void AsyncWaitForVsync(Callback callback) = 0; - 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 AwaitVSync() = 0; + + void FireCallback(fxl::TimePoint frame_start_time, + fxl::TimePoint frame_target_time); + + FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiter); }; } // namespace shell diff --git a/shell/common/vsync_waiter_fallback.cc b/shell/common/vsync_waiter_fallback.cc index 01c86cdedc6aae77b882c12cbabb6aa18527fa62..bcf061bb7615f889ea119f034ed4f8605229c860 100644 --- a/shell/common/vsync_waiter_fallback.cc +++ b/shell/common/vsync_waiter_fallback.cc @@ -4,7 +4,6 @@ #include "flutter/shell/common/vsync_waiter_fallback.h" -#include "flutter/common/threads.h" #include "lib/fxl/logging.h" namespace shell { @@ -21,28 +20,25 @@ fxl::TimePoint SnapToNextTick(fxl::TimePoint value, } // namespace -VsyncWaiterFallback::VsyncWaiterFallback() - : phase_(fxl::TimePoint::Now()), weak_factory_(this) {} +VsyncWaiterFallback::VsyncWaiterFallback(blink::TaskRunners task_runners) + : VsyncWaiter(std::move(task_runners)), + phase_(fxl::TimePoint::Now()), + weak_factory_(this) {} VsyncWaiterFallback::~VsyncWaiterFallback() = default; constexpr fxl::TimeDelta interval = fxl::TimeDelta::FromSecondsF(1.0 / 60.0); -void VsyncWaiterFallback::AsyncWaitForVsync(Callback callback) { - FXL_DCHECK(!callback_); - callback_ = std::move(callback); - +void VsyncWaiterFallback::AwaitVSync() { fxl::TimePoint now = fxl::TimePoint::Now(); fxl::TimePoint next = SnapToNextTick(now, phase_, interval); - blink::Threads::UI()->PostDelayedTask( + task_runners_.GetUITaskRunner()->PostDelayedTask( [self = weak_factory_.GetWeakPtr()] { - 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); + if (self) { + const auto frame_time = fxl::TimePoint::Now(); + self->FireCallback(frame_time, frame_time + interval); + } }, next - now); } diff --git a/shell/common/vsync_waiter_fallback.h b/shell/common/vsync_waiter_fallback.h index bfb7e118b1330875bff2bd4967c38b3464abb6cd..d3cc8faaf6ce7d21838477091ac093b338a96e22 100644 --- a/shell/common/vsync_waiter_fallback.h +++ b/shell/common/vsync_waiter_fallback.h @@ -5,25 +5,24 @@ #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 : public VsyncWaiter { +class VsyncWaiterFallback final : public VsyncWaiter { public: - VsyncWaiterFallback(); - ~VsyncWaiterFallback() override; + VsyncWaiterFallback(blink::TaskRunners task_runners); - void AsyncWaitForVsync(Callback callback) override; + ~VsyncWaiterFallback() override; private: fxl::TimePoint phase_; - Callback callback_; + fxl::WeakPtrFactory weak_factory_; - fml::WeakPtrFactory weak_factory_; + void AwaitVSync() override; FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterFallback); }; diff --git a/shell/gpu/BUILD.gn b/shell/gpu/BUILD.gn index c050e120b0a108b7119428a102336d9741caf5e5..cd093e1238f7f0c1aac93630341af9aa88bfce72 100644 --- a/shell/gpu/BUILD.gn +++ b/shell/gpu/BUILD.gn @@ -6,14 +6,17 @@ 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 deleted file mode 100644 index 3424f989b32050ca2e2ede7f24df1e75a20fbe9f..0000000000000000000000000000000000000000 --- a/shell/gpu/gpu_rasterizer.cc +++ /dev/null @@ -1,168 +0,0 @@ -// 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 deleted file mode 100644 index ad16ee2c479898412d9344c66e6c374f91c1f318..0000000000000000000000000000000000000000 --- a/shell/gpu/gpu_rasterizer.h +++ /dev/null @@ -1,68 +0,0 @@ -// 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 331fd188a9ed3d00f356c423616b2963ef48ee94..284a10e413b46a9aeefe97b4cf88b68c2471a7ba 100644 --- a/shell/gpu/gpu_surface_gl.cc +++ b/shell/gpu/gpu_surface_gl.cc @@ -72,6 +72,8 @@ GPUSurfaceGL::~GPUSurfaceGL() { return; } + GetCompositorContext().OnGrContextDestroyed(); + onscreen_surface_ = nullptr; context_->releaseResourcesAndAbandonContext(); context_ = nullptr; @@ -210,12 +212,11 @@ std::unique_ptr GPUSurfaceGL::AcquireFrame(const SkISize& size) { return nullptr; } - 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; - }; + SurfaceFrame::SubmitCallback submit_callback = [weak = weak_factory_ + .GetWeakPtr()]( + const SurfaceFrame& surface_frame, SkCanvas* canvas) { + return weak ? weak->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 5cf092dae66c53a6328964f10a2c02208087ac1d..abc9f46aee29778f7c2bfd19560c716b3d05ce59 100644 --- a/shell/gpu/gpu_surface_gl.h +++ b/shell/gpu/gpu_surface_gl.h @@ -5,10 +5,9 @@ #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 { @@ -44,7 +43,7 @@ class GPUSurfaceGL : public Surface { sk_sp onscreen_surface_; sk_sp offscreen_surface_; bool valid_ = false; - fml::WeakPtrFactory weak_factory_; + fxl::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 e340e605652ddcffd550cdf8b6b809c465373d38..ea8c827b2240525fb21a95d6c6f73d12c40083ab 100644 --- a/shell/gpu/gpu_surface_software.cc +++ b/shell/gpu/gpu_surface_software.cc @@ -18,20 +18,13 @@ 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; } - // 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); + const auto size = SkISize::Make(logical_size.width(), logical_size.height()); sk_sp backing_store = delegate_->AcquireBackingStore(size); @@ -48,12 +41,10 @@ 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 f7312153db8bcaf7b9fe36f66727c05b1fc1d85e..238754f312b804bd841b158488f75a2758277f3f 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,12 +30,9 @@ class GPUSurfaceSoftware : public Surface { GrContext* GetContext() override; - bool SupportsScaling() const override; - private: GPUSurfaceSoftwareDelegate* delegate_; - - fml::WeakPtrFactory weak_factory_; + fxl::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 eafed43a6296d91fe7a640cae61cfd319caad64c..f1e25fbe987b8853edeca0de9c28d02b3eb765d8 100644 --- a/shell/gpu/gpu_surface_vulkan.h +++ b/shell/gpu/gpu_surface_vulkan.h @@ -6,11 +6,12 @@ #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 { @@ -29,7 +30,7 @@ class GPUSurfaceVulkan : public Surface { private: vulkan::VulkanWindow window_; - fml::WeakPtrFactory weak_factory_; + fxl::WeakPtrFactory weak_factory_; FXL_DISALLOW_COPY_AND_ASSIGN(GPUSurfaceVulkan); }; diff --git a/shell/platform/BUILD.gn b/shell/platform/BUILD.gn index 4b1e1a9e0bfeb60b1b361b6d30cfbd99365a7e21..ae3b1003f22fe66cbb76822f146e9bd80a4fbfd1 100644 --- a/shell/platform/BUILD.gn +++ b/shell/platform/BUILD.gn @@ -13,13 +13,11 @@ group("platform") { ] } else if (is_linux) { deps = [ - "linux", "embedder", ] } else if (is_win) { - deps = [ - "win" - ] + # There is no platform target on windows. Instead, only a tester is used. + deps = [] } else { assert(false, "Unknown/Unsupported platform.") } diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index d9744ad890caaa33276c9f090467a76e125a150f..129c877faed0f75d5c6949bdd2cfc24edc2aa115 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -17,21 +17,25 @@ shared_library("flutter_shell_native") { "android_context_gl.h", "android_environment_gl.cc", "android_environment_gl.h", - "android_external_texture_gl.h", "android_external_texture_gl.cc", + "android_external_texture_gl.h", "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.h", "android_surface_software.cc", - "apk_asset_provider.h", + "android_surface_software.h", "apk_asset_provider.cc", + "apk_asset_provider.h", "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", @@ -41,10 +45,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", @@ -59,9 +63,7 @@ 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 f54629f8644b9828e841e3b185cd6d9459f2796a..6338dc96908e124e0cf888455cd873c6b0ac93f6 100644 --- a/shell/platform/android/android_context_gl.cc +++ b/shell/platform/android/android_context_gl.cc @@ -3,9 +3,13 @@ // 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 @@ -65,19 +69,17 @@ static EGLResult CreateContext(EGLDisplay display, return {context != EGL_NO_CONTEXT, context}; } -static EGLResult ChooseEGLConfiguration( - EGLDisplay display, - PlatformView::SurfaceConfig config) { +static EGLResult ChooseEGLConfiguration(EGLDisplay display) { EGLint attributes[] = { // clang-format off EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - 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_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 0, + EGL_STENCIL_SIZE, 0, EGL_NONE, // termination sentinel // clang-format on }; @@ -142,7 +144,6 @@ bool AndroidContextGL::CreatePBufferSurface() { } AndroidContextGL::AndroidContextGL(fxl::RefPtr env, - PlatformView::SurfaceConfig config, const AndroidContextGL* share_context) : environment_(env), window_(nullptr), @@ -158,8 +159,7 @@ AndroidContextGL::AndroidContextGL(fxl::RefPtr env, // Choose a valid configuration. - std::tie(success, config_) = - ChooseEGLConfiguration(environment_->Display(), config); + std::tie(success, config_) = ChooseEGLConfiguration(environment_->Display()); 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 207f621c66bd1ebd288f5b9aae8697e2f96601b0..b29851b34564daf21d0a74fa3fc84d63b9df0e87 100644 --- a/shell/platform/android/android_context_gl.h +++ b/shell/platform/android/android_context_gl.h @@ -44,7 +44,6 @@ 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 02a40c22474a13e535e854737adbccd538cc0052..35db9cbbfdb9561556c22034a8dc70721d9e0d18 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,17 +19,14 @@ 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; } @@ -42,7 +39,8 @@ 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, @@ -82,7 +80,6 @@ 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 df890b91c827f4a87a6d35a65d82834c93d3dde3..67d6541d964c25d48966c2abd2122c59a018b63f 100644 --- a/shell/platform/android/android_external_texture_gl.h +++ b/shell/platform/android/android_external_texture_gl.h @@ -25,8 +25,7 @@ class AndroidExternalTextureGL : public flow::Texture { virtual void OnGrContextDestroyed() override; - // Called on GPU thread. - void MarkNewFrameAvailable(); + void MarkNewFrameAvailable() override; private: void Attach(jint textureName); diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc new file mode 100644 index 0000000000000000000000000000000000000000..7dc454f1fb74a66e75e06dab90833c25cd69a8c1 --- /dev/null +++ b/shell/platform/android/android_shell_holder.cc @@ -0,0 +1,169 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..e0905f0f9e42ecb95a0460e171094346a6718c48 --- /dev/null +++ b/shell/platform/android/android_shell_holder.h @@ -0,0 +1,59 @@ +// 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 4dd08609da370c914f2c8ace7572c06d64974fde..a8b41bacbf7c514ada3538257d3e92cbbcc1e39f 100644 --- a/shell/platform/android/android_surface.cc +++ b/shell/platform/android/android_surface.cc @@ -4,8 +4,32 @@ #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 2425a61e207078fafac06bcdd077c475d1cef4a8..858b07eb45d9f2173bd9d6ecb3585b17d00a8106 100644 --- a/shell/platform/android/android_surface.h +++ b/shell/platform/android/android_surface.h @@ -19,6 +19,8 @@ namespace shell { class AndroidSurface { public: + static std::unique_ptr Create(bool use_software_rendering); + virtual ~AndroidSurface(); virtual bool IsValid() const = 0; @@ -27,14 +29,11 @@ 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, - PlatformView::SurfaceConfig config = {}) = 0; + virtual bool SetNativeWindow(fxl::RefPtr window) = 0; }; } // namespace shell diff --git a/shell/platform/android/android_surface_gl.cc b/shell/platform/android/android_surface_gl.cc index f30ac1272b043d583c32b4d9d2a7d60b9d072ee2..274b652a97b748714ed6d09150968e90ab84292d 100644 --- a/shell/platform/android/android_surface_gl.cc +++ b/shell/platform/android/android_surface_gl.cc @@ -6,14 +6,12 @@ #include -#include "flutter/common/threads.h" #include "lib/fxl/logging.h" #include "lib/fxl/memory/ref_ptr.h" namespace shell { -static fxl::RefPtr GlobalResourceLoadingContext( - PlatformView::SurfaceConfig offscreen_config) { +static fxl::RefPtr GlobalResourceLoadingContext() { // AndroidSurfaceGL instances are only ever created on the platform thread. So // there is no need to lock here. @@ -29,11 +27,7 @@ static fxl::RefPtr GlobalResourceLoadingContext( return nullptr; } - // TODO(chinmaygarde): We should check that the configurations are stable - // across multiple invocations. - - auto context = - fxl::MakeRefCounted(environment, offscreen_config); + auto context = fxl::MakeRefCounted(environment); if (!context->IsValid()) { return nullptr; @@ -43,10 +37,9 @@ static fxl::RefPtr GlobalResourceLoadingContext( return global_context; } -AndroidSurfaceGL::AndroidSurfaceGL( - PlatformView::SurfaceConfig offscreen_config) { +AndroidSurfaceGL::AndroidSurfaceGL() { // Acquire the offscreen context. - offscreen_context_ = GlobalResourceLoadingContext(offscreen_config); + offscreen_context_ = GlobalResourceLoadingContext(); if (!offscreen_context_ || !offscreen_context_->IsValid()) { offscreen_context_ = nullptr; @@ -60,14 +53,9 @@ bool AndroidSurfaceGL::IsOffscreenContextValid() const { } void AndroidSurfaceGL::TeardownOnScreenContext() { - fxl::AutoResetWaitableEvent latch; - blink::Threads::Gpu()->PostTask([this, &latch]() { - if (IsValid()) { - GLContextClearCurrent(); - } - latch.Signal(); - }); - latch.Wait(); + if (onscreen_context_) { + onscreen_context_->ClearCurrent(); + } onscreen_context_ = nullptr; } @@ -84,11 +72,6 @@ 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); @@ -99,8 +82,8 @@ bool AndroidSurfaceGL::ResourceContextMakeCurrent() { return offscreen_context_->MakeCurrent(); } -bool AndroidSurfaceGL::SetNativeWindow(fxl::RefPtr window, - PlatformView::SurfaceConfig config) { +bool AndroidSurfaceGL::SetNativeWindow( + fxl::RefPtr window) { // In any case, we want to get rid of our current onscreen context. onscreen_context_ = nullptr; @@ -112,7 +95,7 @@ bool AndroidSurfaceGL::SetNativeWindow(fxl::RefPtr window, // Create the onscreen context. onscreen_context_ = fxl::MakeRefCounted( - offscreen_context_->Environment(), config, + offscreen_context_->Environment(), 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 08aee081c82663c7a9a7f390b95e37625a793e8f..e26f2bf50d3a938a241a4de1648f5589b7bf4fcc 100644 --- a/shell/platform/android/android_surface_gl.h +++ b/shell/platform/android/android_surface_gl.h @@ -16,35 +16,43 @@ namespace shell { -class AndroidSurfaceGL : public GPUSurfaceGLDelegate, public AndroidSurface { +class AndroidSurfaceGL final : public GPUSurfaceGLDelegate, + public AndroidSurface { public: - explicit AndroidSurfaceGL(PlatformView::SurfaceConfig offscreen_config); + AndroidSurfaceGL(); ~AndroidSurfaceGL() override; - bool IsValid() const override; - bool IsOffscreenContextValid() const; + // |shell::AndroidSurface| + bool IsValid() const override; + + // |shell::AndroidSurface| 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; - bool SetNativeWindow(fxl::RefPtr window, - PlatformView::SurfaceConfig config) override; + // |shell::AndroidSurface| + bool SetNativeWindow(fxl::RefPtr window) 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 68bf99b27ba56426fb19b32b71c795657dfa1787..4b1378802d9e47f375e33b622925cbe3492a5d58 100644 --- a/shell/platform/android/android_surface_software.cc +++ b/shell/platform/android/android_surface_software.cc @@ -3,15 +3,14 @@ // 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 { @@ -132,17 +131,12 @@ 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, - PlatformView::SurfaceConfig config) { + fxl::RefPtr window) { 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 76184b707cf7423c0db8f61de84f1bb4337824aa..0f82fc5dfe1543644af4bed4f580cffd651a5a57 100644 --- a/shell/platform/android/android_surface_software.h +++ b/shell/platform/android/android_surface_software.h @@ -13,35 +13,39 @@ namespace shell { -class AndroidSurfaceSoftware : public AndroidSurface, - public GPUSurfaceSoftwareDelegate { +class AndroidSurfaceSoftware final : 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; - sk_sp AcquireBackingStore(const SkISize& size) override; - - bool PresentBackingStore(sk_sp backing_store) override; - + // |shell::AndroidSurface| void TeardownOnScreenContext() override; - SkISize OnScreenSurfaceSize() const override; - + // |shell::AndroidSurface| bool OnScreenSurfaceResize(const SkISize& size) const override; - bool SetNativeWindow(fxl::RefPtr window, - PlatformView::SurfaceConfig config) override; + // |shell::AndroidSurface| + bool SetNativeWindow(fxl::RefPtr window) override; + + // |shell::GPUSurfaceSoftwareDelegate| + sk_sp AcquireBackingStore(const SkISize& size) override; + + // |shell::GPUSurfaceSoftwareDelegate| + bool PresentBackingStore(sk_sp backing_store) 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 ccacf538b8781a2f8d7fbecbabefa27ecf8284ce..e8817690188c2b4189d876bde86c8f01b478ca2c 100644 --- a/shell/platform/android/android_surface_vulkan.cc +++ b/shell/platform/android/android_surface_vulkan.cc @@ -21,10 +21,12 @@ 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; @@ -52,21 +54,20 @@ std::unique_ptr AndroidSurfaceVulkan::CreateGPUSurface() { return gpu_surface; } -SkISize AndroidSurfaceVulkan::OnScreenSurfaceSize() const { - return native_window_ ? native_window_->GetSize() : SkISize::Make(0, 0); -} - +// |shell::AndroidSurface| 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, - PlatformView::SurfaceConfig config) { + fxl::RefPtr window) { 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 f1ecf610c858442c8ef79e7f8e6dc4eab507582a..fd3f493d497904b1f2f860b655ab6923dab6285a 100644 --- a/shell/platform/android/android_surface_vulkan.h +++ b/shell/platform/android/android_surface_vulkan.h @@ -20,20 +20,23 @@ class AndroidSurfaceVulkan : public AndroidSurface { ~AndroidSurfaceVulkan() override; + // |shell::AndroidSurface| bool IsValid() const override; - void TeardownOnScreenContext() override; - + // |shell::AndroidSurface| std::unique_ptr CreateGPUSurface() override; - SkISize OnScreenSurfaceSize() const override; + // |shell::AndroidSurface| + void TeardownOnScreenContext() override; + // |shell::AndroidSurface| bool OnScreenSurfaceResize(const SkISize& size) const override; + // |shell::AndroidSurface| bool ResourceContextMakeCurrent() override; - bool SetNativeWindow(fxl::RefPtr window, - PlatformView::SurfaceConfig config) override; + // |shell::AndroidSurface| + bool SetNativeWindow(fxl::RefPtr window) 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 fdd4910a12f4cc50f41227b40b198049fe548be9..4cf6da16dc64f0510a456cbcdb219c7bec715635 100644 --- a/shell/platform/android/apk_asset_provider.cc +++ b/shell/platform/android/apk_asset_provider.cc @@ -7,32 +7,41 @@ 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) { + std::vector* data) const { 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 c40b1ed2a186652ff960b901f2ea60de4882d066..70ddbe454bc615322bcd4bf65d595a14061631b6 100644 --- a/shell/platform/android/apk_asset_provider.h +++ b/shell/platform/android/apk_asset_provider.h @@ -5,28 +5,35 @@ #ifndef FLUTTER_ASSETS_APK_ASSET_PROVIDER_H_ #define FLUTTER_ASSETS_APK_ASSET_PROVIDER_H_ -#include #include +#include -#include "flutter/assets/asset_provider.h" +#include "flutter/assets/asset_resolver.h" #include "lib/fxl/memory/ref_counted.h" namespace blink { -class APKAssetProvider - : public AssetProvider { +class APKAssetProvider final : public AssetResolver { 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); + std::vector* data) const override; - private: - AAssetManager* assetManager_; - const std::string directory_; + FXL_DISALLOW_COPY_AND_ASSIGN(APKAssetProvider); }; } // 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 6df346a12872223e9961e60f60614245196c540d..08d97add93b87e65a02472084561a349bc39e406 100644 --- a/shell/platform/android/flutter_main.cc +++ b/shell/platform/android/flutter_main.cc @@ -2,38 +2,85 @@ // 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 { -static void Init(JNIEnv* env, - jclass clazz, - jobject context, - jobjectArray jargs, - jstring bundlePath) { - // Prepare command line arguments and initialize the 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) { std::vector args; - args.push_back("flutter_tester"); + args.push_back("flutter"); for (auto& arg : fml::jni::StringArrayToVector(env, jargs)) { args.push_back(std::move(arg)); } - 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)); + + 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))); } static void RecordStartTimestamp(JNIEnv* env, @@ -44,7 +91,7 @@ static void RecordStartTimestamp(JNIEnv* env, blink::engine_main_enter_ts = Dart_TimelineGetMicros() - initTimeMicros; } -bool RegisterFlutterMain(JNIEnv* env) { +bool FlutterMain::Register(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 f4f65c499f966ea6eb92644cd1ce773593c831f8..6c8717e9cebdb4aba0acf0389b371dcea29c6441 100644 --- a/shell/platform/android/flutter_main.h +++ b/shell/platform/android/flutter_main.h @@ -7,9 +7,34 @@ #include +#include "flutter/common/settings.h" +#include "lib/fxl/macros.h" + namespace shell { -bool RegisterFlutterMain(JNIEnv* env); +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); +}; } // namespace shell diff --git a/shell/platform/android/library_loader.cc b/shell/platform/android/library_loader.cc index c51d0114282f677bea358ddec669895b71b37e20..569825ce33e21475cfefec926bdc8d69c6978008 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::RegisterFlutterMain(env); + result = shell::FlutterMain::Register(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 new file mode 100644 index 0000000000000000000000000000000000000000..214080ec5bde37ef3c532a0511965949bc640a4d --- /dev/null +++ b/shell/platform/android/platform_message_response_android.cc @@ -0,0 +1,62 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..2ee7f3336ac6d6d92ac57381f7d39c388ebd2a60 --- /dev/null +++ b/shell/platform/android/platform_message_response_android.h @@ -0,0 +1,39 @@ +// 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 8f677045fb1f55dc7501311741cf811510973fc0..00d1e4b59e8489b26c6e831f8f640ca01ee597d1 100644 --- a/shell/platform/android/platform_view_android.cc +++ b/shell/platform/android/platform_view_android.cc @@ -4,288 +4,55 @@ #include "flutter/shell/platform/android/platform_view_android.h" -#include -#include -#include -#include - +#include #include -#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/common/io_manager.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/android_surface_software.h" -#include "flutter/shell/platform/android/apk_asset_provider.h" +#include "flutter/shell/platform/android/platform_message_response_android.h" #include "flutter/shell/platform/android/platform_view_android_jni.h" #include "flutter/shell/platform/android/vsync_waiter_android.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 +#include "lib/fxl/synchronization/waitable_event.h" namespace shell { -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 +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."; } -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::Attach() { - CreateEngine(); - - // Eagerly setup the IO thread context. We have already setup the surface. - SetupResourceContextOnIOThread(); - - UpdateThreadPriorities(); +void PlatformViewAndroid::NotifyCreated( + fxl::RefPtr native_window) { + InstallFirstFrameCallback(); + android_surface_->SetNativeWindow(native_window); + PlatformView::NotifyCreated(); } -void PlatformViewAndroid::Detach() { - ReleaseSurface(); -} - -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); - }); -} - -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::NotifyDestroyed() { + PlatformView::NotifyDestroyed(); + android_surface_->TeardownOnScreenContext(); } -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::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::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); - }); + latch.Wait(); } void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env, @@ -301,7 +68,7 @@ void PlatformViewAndroid::DispatchPlatformMessage(JNIEnv* env, fxl::RefPtr response; if (response_id) { response = fxl::MakeRefCounted( - response_id, GetWeakPtr()); + response_id, java_object_, task_runners_.GetPlatformTaskRunner()); } PlatformView::DispatchPlatformMessage( @@ -315,7 +82,7 @@ void PlatformViewAndroid::DispatchEmptyPlatformMessage(JNIEnv* env, fxl::RefPtr response; if (response_id) { response = fxl::MakeRefCounted( - response_id, GetWeakPtr()); + response_id, java_object_, task_runners_.GetPlatformTaskRunner()); } PlatformView::DispatchPlatformMessage( @@ -323,20 +90,6 @@ 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, @@ -369,10 +122,11 @@ void PlatformViewAndroid::InvokePlatformMessageEmptyResponseCallback( message_response->CompleteEmpty(); } +// |shell::PlatformView| void PlatformViewAndroid::HandlePlatformMessage( fxl::RefPtr message) { JNIEnv* env = fml::jni::AttachCurrentThread(); - fml::jni::ScopedJavaLocalRef view = flutter_view_.get(env); + fml::jni::ScopedJavaLocalRef view = java_object_.get(env); if (view.is_null()) return; @@ -402,35 +156,6 @@ 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, @@ -451,35 +176,14 @@ void PlatformViewAndroid::DispatchSemanticsAction(JNIEnv* env, id, static_cast(action), std::move(args_vector)); } -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) { +// |shell::PlatformView| +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 = flutter_view_.get(env); + fml::jni::ScopedJavaLocalRef view = java_object_.get(env); if (view.is_null()) return; @@ -560,79 +264,6 @@ void PlatformViewAndroid::UpdateSemantics( } } -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) { @@ -640,116 +271,56 @@ void PlatformViewAndroid::RegisterExternalTexture( std::make_shared(texture_id, surface_texture)); } -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::CreateVSyncWaiter() { + return std::make_unique(task_runners_); } -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(); - }); - - latch.Wait(); - - // 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); +// |shell::PlatformView| +std::unique_ptr PlatformViewAndroid::CreateRenderingSurface() { + return android_surface_->CreateGPUSurface(); +} - jobject bitmap = env->CallStaticObjectMethod( - bitmap_class, create_bitmap, pixels.obj(), frame_size.width(), - frame_size.height(), bitmap_config); +// |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."; + } - return fml::jni::ScopedJavaLocalRef(env, bitmap); + 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(); + } + }); + }); } -void PlatformViewAndroid::GetBitmapGpuTask(jobject* pixels_out, - SkISize* size_out) { - flow::LayerTree* layer_tree = rasterizer_->GetLastLayerTree(); - if (layer_tree == nullptr) - return; - +void PlatformViewAndroid::FireFirstFrameCallback() { 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]); + fml::jni::ScopedJavaLocalRef view = java_object_.get(env); + if (view.is_null()) { + // The Java object died. + return; } - - env->ReleaseIntArrayElements(pixels_array, pixels, 0); - - *pixels_out = env->NewGlobalRef(pixels_array); - *size_out = frame_size; - - fml::jni::DetachFromVM(); + FlutterViewOnFirstFrame(fml::jni::AttachCurrentThread(), view.obj()); } } // namespace shell diff --git a/shell/platform/android/platform_view_android.h b/shell/platform/android/platform_view_android.h index 4779ea16ab4a736e061692c3c1b4cc211db99c4c..9976c443f4248aa35fd20d0653c0b433eaea43b2 100644 --- a/shell/platform/android/platform_view_android.h +++ b/shell/platform/android/platform_view_android.h @@ -20,45 +20,23 @@ namespace shell { -class PlatformViewAndroid : public PlatformView { +class PlatformViewAndroid final : public PlatformView { public: static bool Register(JNIEnv* env); - PlatformViewAndroid(); + PlatformViewAndroid(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + fml::jni::JavaObjectWeakGlobalRef java_object, + bool use_software_rendering); ~PlatformViewAndroid() override; - virtual void Attach() override; + void NotifyCreated(fxl::RefPtr native_window); - void Detach(); + void NotifyChanged(const SkISize& size); - 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); + // |shell::PlatformView| + void NotifyDestroyed() override; void DispatchPlatformMessage(JNIEnv* env, std::string name, @@ -70,8 +48,6 @@ class PlatformViewAndroid : 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, @@ -86,55 +62,37 @@ class PlatformViewAndroid : 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: - std::unique_ptr android_surface_; - fml::jni::JavaObjectWeakGlobalRef flutter_view_; + const fml::jni::JavaObjectWeakGlobalRef java_object_; + const std::unique_ptr android_surface_; // We use id 0 to mean that no response is expected. int next_response_id_ = 1; std::unordered_map> pending_responses_; - void UpdateThreadPriorities(); + // |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 ReleaseSurface(); + void InstallFirstFrameCallback(); - void GetBitmapGpuTask(jobject* pixels_out, SkISize* size_out); + void FireFirstFrameCallback(); 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 c819f3bfb5e41fb2451a0d6eeaf433a31affb2ed..f75f54a896850a36bd44fa38d0512b2970143647 100644 --- a/shell/platform/android/platform_view_android_jni.cc +++ b/shell/platform/android/platform_view_android_jni.cc @@ -4,17 +4,26 @@ #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 PLATFORM_VIEW \ - (*reinterpret_cast*>(platform_view)) +#define ANDROID_SHELL_HOLDER \ + (reinterpret_cast(shell_holder)) namespace shell { @@ -78,14 +87,12 @@ 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)); } @@ -94,14 +101,12 @@ 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)); } @@ -109,22 +114,22 @@ void SurfaceTextureDetachFromGLContext(JNIEnv* env, jobject obj) { // Called By Java static jlong Attach(JNIEnv* env, jclass clazz, jobject flutterView) { - 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); + 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; + } } -static void Detach(JNIEnv* env, jobject jcaller, jlong platform_view) { - PLATFORM_VIEW->Detach(); +static void Detach(JNIEnv* env, jobject jcaller, jlong shell_holder) { + // Nothing to do. } -static void Destroy(JNIEnv* env, jobject jcaller, jlong platform_view) { - PLATFORM_VIEW->Detach(); - delete &PLATFORM_VIEW; +static void Destroy(JNIEnv* env, jobject jcaller, jlong shell_holder) { + delete ANDROID_SHELL_HOLDER; } static jstring GetObservatoryUri(JNIEnv* env, jclass clazz) { @@ -134,67 +139,180 @@ static jstring GetObservatoryUri(JNIEnv* env, jclass clazz) { static void SurfaceCreated(JNIEnv* env, jobject jcaller, - jlong platform_view, - jobject surface, + jlong shell_holder, + jobject jsurface, jint backgroundColor) { - return PLATFORM_VIEW->SurfaceCreated(env, surface, 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)); } static void SurfaceChanged(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jint width, jint height) { - 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 - ); + ANDROID_SHELL_HOLDER->GetPlatformView()->NotifyChanged( + SkISize::Make(width, height)); } -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)); +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)); +} + +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 SetAssetBundlePathOnUI(JNIEnv* env, jobject jcaller, - jlong platform_view, - jstring bundlePath) { - return PLATFORM_VIEW->SetAssetBundlePathOnUI( - fml::jni::JavaStringToString(env, bundlePath)); + 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)); } static void SetViewportMetrics(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jfloat devicePixelRatio, jint physicalWidth, jint physicalHeight, @@ -206,115 +324,194 @@ static void SetViewportMetrics(JNIEnv* env, jint physicalViewInsetRight, jint physicalViewInsetBottom, jint physicalViewInsetLeft) { - return PLATFORM_VIEW->SetViewportMetrics(devicePixelRatio, // - physicalWidth, // - physicalHeight, // - physicalPaddingTop, // - physicalPaddingRight, // - physicalPaddingBottom, // - physicalPaddingLeft, // - physicalViewInsetTop, // - physicalViewInsetRight, // - physicalViewInsetBottom, // - 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); } -static jobject GetBitmap(JNIEnv* env, jobject jcaller, jlong platform_view) { - return PLATFORM_VIEW->GetBitmap(env).Release(); +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 void DispatchPlatformMessage(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jstring channel, jobject message, jint position, jint responseId) { - return PLATFORM_VIEW->DispatchPlatformMessage( - env, fml::jni::JavaStringToString(env, channel), message, position, - responseId); + ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchPlatformMessage( + env, // + fml::jni::JavaStringToString(env, channel), // + message, // + position, // + responseId // + ); } static void DispatchEmptyPlatformMessage(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jstring channel, jint responseId) { - return PLATFORM_VIEW->DispatchEmptyPlatformMessage( - env, fml::jni::JavaStringToString(env, channel), responseId); + ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchEmptyPlatformMessage( + env, // + fml::jni::JavaStringToString(env, channel), // + responseId // + ); } static void DispatchPointerDataPacket(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jobject buffer, jint position) { - return PLATFORM_VIEW->DispatchPointerDataPacket(env, buffer, position); + uint8_t* data = static_cast(env->GetDirectBufferAddress(buffer)); + auto packet = std::make_unique(data, position); + ANDROID_SHELL_HOLDER->DispatchPointerDataPacket(std::move(packet)); } static void DispatchSemanticsAction(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jint id, jint action, jobject args, jint args_position) { - return PLATFORM_VIEW->DispatchSemanticsAction(env, id, action, args, - args_position); + ANDROID_SHELL_HOLDER->GetPlatformView()->DispatchSemanticsAction( + env, // + id, // + action, // + args, // + args_position // + ); } static void SetSemanticsEnabled(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jboolean enabled) { - return PLATFORM_VIEW->SetSemanticsEnabled(enabled); + ANDROID_SHELL_HOLDER->GetPlatformView()->SetSemanticsEnabled(enabled); } static jboolean GetIsSoftwareRendering(JNIEnv* env, jobject jcaller) { - return blink::Settings::Get().enable_software_rendering; + return FlutterMain::Get().GetSettings().enable_software_rendering; } static void RegisterTexture(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jlong texture_id, jobject surface_texture) { - PLATFORM_VIEW->RegisterExternalTexture( - static_cast(texture_id), - fml::jni::JavaObjectWeakGlobalRef(env, surface_texture)); + ANDROID_SHELL_HOLDER->GetPlatformView()->RegisterExternalTexture( + static_cast(texture_id), // + fml::jni::JavaObjectWeakGlobalRef(env, surface_texture) // + ); } static void MarkTextureFrameAvailable(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jlong texture_id) { - return PLATFORM_VIEW->MarkTextureFrameAvailable( + ANDROID_SHELL_HOLDER->GetPlatformView()->MarkTextureFrameAvailable( static_cast(texture_id)); } static void UnregisterTexture(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jlong texture_id) { - PLATFORM_VIEW->UnregisterTexture(static_cast(texture_id)); + ANDROID_SHELL_HOLDER->GetPlatformView()->UnregisterTexture( + static_cast(texture_id)); } static void InvokePlatformMessageResponseCallback(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jint responseId, jobject message, jint position) { - return PLATFORM_VIEW->InvokePlatformMessageResponseCallback( - env, responseId, message, position); + ANDROID_SHELL_HOLDER->GetPlatformView() + ->InvokePlatformMessageResponseCallback(env, // + responseId, // + message, // + position // + ); } static void InvokePlatformMessageEmptyResponseCallback(JNIEnv* env, jobject jcaller, - jlong platform_view, + jlong shell_holder, jint responseId) { - return PLATFORM_VIEW->InvokePlatformMessageEmptyResponseCallback(env, - responseId); + ANDROID_SHELL_HOLDER->GetPlatformView() + ->InvokePlatformMessageEmptyResponseCallback(env, // + responseId // + ); } bool PlatformViewAndroid::Register(JNIEnv* env) { @@ -353,8 +550,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), }, { @@ -373,11 +570,6 @@ 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 29e1958dcc011d7e2496d9642436a4dcfe1c8565..052de023b9a1293d15bd1ed9d1d8623cf5289dd4 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/threads.h" +#include "flutter/common/task_runners.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,68 +16,49 @@ 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() : weak_factory_(this) {} +VsyncWaiterAndroid::VsyncWaiterAndroid(blink::TaskRunners task_runners) + : VsyncWaiter(std::move(task_runners)) {} VsyncWaiterAndroid::~VsyncWaiterAndroid() = default; -void VsyncWaiterAndroid::AsyncWaitForVsync(Callback callback) { - FXL_DCHECK(!callback_); - callback_ = std::move(callback); - fml::WeakPtr* weak = - new fml::WeakPtr(); - *weak = weak_factory_.GetWeakPtr(); +// |shell::VsyncWaiter| +void VsyncWaiterAndroid::AwaitVSync() { + auto java_baton = + CreatePendingCallback(std::bind(&VsyncWaiterAndroid::FireCallback, // + this, // + std::placeholders::_1, // + std::placeholders::_2 // + )); - blink::Threads::Platform()->PostTask([weak] { + task_runners_.GetPlatformTaskRunner()->PostTask([java_baton]() { JNIEnv* env = fml::jni::AttachCurrentThread(); - env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), - g_async_wait_for_vsync_method_, - reinterpret_cast(weak)); + env->CallStaticVoidMethod(g_vsync_waiter_class->obj(), // + g_async_wait_for_vsync_method_, // + java_baton // + ); }); } -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 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)); - } + 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); } bool VsyncWaiterAndroid::Register(JNIEnv* env) { @@ -105,4 +86,27 @@ 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 c73af4bfca6f0764ee2d0d5169fadc9c67cf2ff3..fd72a0a21f563be80e334c101fd233caecb288b0 100644 --- a/shell/platform/android/vsync_waiter_android.h +++ b/shell/platform/android/vsync_waiter_android.h @@ -12,22 +12,17 @@ namespace shell { -class VsyncWaiterAndroid : public VsyncWaiter { +class VsyncWaiterAndroid final : public VsyncWaiter { public: - VsyncWaiterAndroid(); - - ~VsyncWaiterAndroid() override; - static bool Register(JNIEnv* env); - void AsyncWaitForVsync(Callback callback) override; + VsyncWaiterAndroid(blink::TaskRunners task_runners); - void OnVsync(int64_t frameTimeNanos, int64_t frameTargetTimeNanos); + ~VsyncWaiterAndroid() override; private: - Callback callback_; - fml::WeakPtr self_; - fml::WeakPtrFactory weak_factory_; + // |shell::VsyncWaiter| + void AwaitVSync() override; FXL_DISALLOW_COPY_AND_ASSIGN(VsyncWaiterAndroid); }; diff --git a/shell/platform/darwin/BUILD.gn b/shell/platform/darwin/BUILD.gn index c971c443bcc306352610d48f9ac503a2d599e8e0..c6f7acd6be76a82652da3b12235ddc02d783197a 100644 --- a/shell/platform/darwin/BUILD.gn +++ b/shell/platform/darwin/BUILD.gn @@ -6,11 +6,8 @@ assert(is_mac || is_ios) group("darwin") { if (is_mac) { - deps = [ - "desktop:shell_standalone", - ] if (!is_fuchsia_host) { - deps += [ + deps = [ "desktop:shell_application_bundle", ] } @@ -45,15 +42,12 @@ 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") { @@ -68,7 +62,7 @@ executable("flutter_channels_unittests") { deps = [ ":flutter_channels", - "//third_party/dart/runtime:libdart_jit", "$flutter_root/testing", + "//third_party/dart/runtime:libdart_jit", ] } diff --git a/shell/platform/darwin/common/BUILD.gn b/shell/platform/darwin/common/BUILD.gn index e6fa86366b0804b1c40763cff0e79bc63ef1f7d5..a1023737973a7b28eff15ae0498bd15dba19520e 100644 --- a/shell/platform/darwin/common/BUILD.gn +++ b/shell/platform/darwin/common/BUILD.gn @@ -9,28 +9,23 @@ source_set("common") { sources = [ "buffer_conversions.h", "buffer_conversions.mm", - "platform_mac.h", - "platform_mac.mm", - "process_info_mac.cc", - "process_info_mac.h", + "command_line.h", + "command_line.mm", ] 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 new file mode 100644 index 0000000000000000000000000000000000000000..dfc995b90f3789745e3166c4ac79fb3887d8a075 --- /dev/null +++ b/shell/platform/darwin/common/command_line.h @@ -0,0 +1,17 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..bf8d4cc9d40f4fb403a1e00f2f9ff4d74eed2e7c --- /dev/null +++ b/shell/platform/darwin/common/command_line.mm @@ -0,0 +1,21 @@ +// 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 deleted file mode 100644 index 1989b25f11c43f5c077854993b72f1200287efe2..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/common/platform_mac.h +++ /dev/null @@ -1,20 +0,0 @@ -// 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 deleted file mode 100644 index 5af35a430beefda50915bc96e637141cdd015f84..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/common/platform_mac.mm +++ /dev/null @@ -1,160 +0,0 @@ -// 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 deleted file mode 100644 index 11f70f305a3e9f7f8c386fb78f7b940e54cb88cd..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/common/process_info_mac.cc +++ /dev/null @@ -1,36 +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. - -#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 deleted file mode 100644 index 7edc8034173e0eac6a6c6446138194034cfefd4f..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/common/process_info_mac.h +++ /dev/null @@ -1,36 +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. - -#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 a9c05f85ef284e923db6cac4dfbb051ddef59227..5ec3298be4aa4991464871775a89487d9f677cf5 100644 --- a/shell/platform/darwin/desktop/BUILD.gn +++ b/shell/platform/darwin/desktop/BUILD.gn @@ -8,10 +8,8 @@ source_set("mac_desktop_platform") { visibility = [ ":*" ] sources = [ - "flutter_app_delegate.h", - "flutter_app_delegate.m", - "flutter_application.h", - "flutter_application.mm", + "flutter_application_delegate.h", + "flutter_application_delegate.mm", "flutter_window.h", "flutter_window.mm", "main_mac.mm", @@ -22,32 +20,22 @@ 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", - ] -} - -executable("shell_standalone") { - output_name = "flutter_tester" - deps = [ - ":mac_desktop_platform", - ] + public_configs = [ "$flutter_root:config" ] } 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 31d3f1240db6b87fd3160f5a58aefbf6e5f7e243..048afb6dadca2901ec978b08c00462970b375c3f 100644 --- a/shell/platform/darwin/desktop/Info.plist +++ b/shell/platform/darwin/desktop/Info.plist @@ -9,11 +9,11 @@ CFBundleIconFile CFBundleIdentifier - io.flutter + io.flutter.engine CFBundleInfoDictionaryVersion 6.0 CFBundleName - Flutter + Flutter Engine CFBundlePackageType APPL CFBundleShortVersionString @@ -26,9 +26,7 @@ 10.6 NSHumanReadableCopyright Copyright 2015 The Flutter Authors. All rights reserved. - NSMainNibFile - flutter_mac NSPrincipalClass - FlutterApplication + NSApplication diff --git a/shell/platform/darwin/desktop/flutter_app_delegate.h b/shell/platform/darwin/desktop/flutter_app_delegate.h deleted file mode 100644 index d6addcb17d0a4723049c62f9b4786487c962d3bd..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/desktop/flutter_app_delegate.h +++ /dev/null @@ -1,14 +0,0 @@ -// 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 deleted file mode 100644 index 7e2dfd68389f8e74a79fb00b64278b9bf5b243a0..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/desktop/flutter_app_delegate.m +++ /dev/null @@ -1,15 +0,0 @@ -// 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.mm b/shell/platform/darwin/desktop/flutter_application.mm deleted file mode 100644 index 57b1c83ba069a88d7f584d5f75e844ecde4c92cb..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/desktop/flutter_application.mm +++ /dev/null @@ -1,8 +0,0 @@ -// 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.h b/shell/platform/darwin/desktop/flutter_application_delegate.h similarity index 65% rename from shell/platform/darwin/desktop/flutter_application.h rename to shell/platform/darwin/desktop/flutter_application_delegate.h index 6a4167b5f273ab080559f8e84e2cb5696d464b8f..3995557b25e79acc2c5b57ff300ab758bda59020 100644 --- a/shell/platform/darwin/desktop/flutter_application.h +++ b/shell/platform/darwin/desktop/flutter_application_delegate.h @@ -1,13 +1,14 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// 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_DESKTOP_FLUTTER_APPLICATION_H_ -#define FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_H_ +#ifndef FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_DELEGATE_H_ +#define FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_DELEGATE_H_ #import -@interface FlutterApplication : NSApplication +@interface FlutterApplicationDelegate : NSObject + @end -#endif // FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_H_ +#endif // FLUTTER_SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_APPLICATION_DELEGATE_H_ diff --git a/shell/platform/darwin/desktop/flutter_application_delegate.mm b/shell/platform/darwin/desktop/flutter_application_delegate.mm new file mode 100644 index 0000000000000000000000000000000000000000..03076b848b25f6e5a894b6a4ff9a9f9c0ebb1876 --- /dev/null +++ b/shell/platform/darwin/desktop/flutter_application_delegate.mm @@ -0,0 +1,80 @@ +// 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 deleted file mode 100644 index c02ab7912da5a80f178b6395215afe74a1902bfe..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/desktop/flutter_mac.xib +++ /dev/null @@ -1,695 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 851535ba38e9e2e02278cd17a6fa17fc64d416bb..e07fe4eeb752048ef00227b85a77fb4e1f04ce25 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__ -#define __SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW__ +#ifndef SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW_H_ +#define SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW_H_ #import @@ -11,4 +11,4 @@ @end -#endif /* defined(__SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW__) */ +#endif // SHELL_PLATFORM_DARWIN_DESKTOP_FLUTTER_WINDOW_H_ diff --git a/shell/platform/darwin/desktop/flutter_window.mm b/shell/platform/darwin/desktop/flutter_window.mm index ca080e9275742fd4a28109065b57383e26638b6b..4c87200fb38561ae7086dcca5b6bf06ed2503c4a 100644 --- a/shell/platform/darwin/desktop/flutter_window.mm +++ b/shell/platform/darwin/desktop/flutter_window.mm @@ -2,16 +2,25 @@ // 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 "flutter/common/threads.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/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(assign) IBOutlet NSOpenGLView* renderSurface; -@property(getter=isSurfaceSetup) BOOL surfaceSetup; +@property(strong) NSOpenGLView* renderSurface; @end @@ -37,34 +46,130 @@ static inline blink::PointerData::Change PointerChangeFromNSEventPhase(NSEventPh } @implementation FlutterWindow { - std::shared_ptr _platformView; + shell::ThreadHost _thread_host; + std::unique_ptr _shell; bool _mouseIsDown; } -@synthesize renderSurface = _renderSurface; -@synthesize surfaceSetup = _surfaceSetup; +- (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; +} -- (void)awakeFromNib { - [super awakeFromNib]; +static std::string CreateThreadLabel() { + std::stringstream stream; + static int index = 1; + stream << "io.flutter." << index++; + return stream.str(); +} - self.delegate = self; +- (void)setupShell { + FXL_DCHECK(!_shell) << "The shell must not already be set."; - [self updateWindowSize]; + auto thread_label = CreateThreadLabel(); + + // 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}; + + // 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]; } -- (void)setupPlatformView { - FXL_DCHECK(_platformView == nullptr) << "The platform view must not already be set."; +- (void)notifySurfaceCreated { + if (!_shell || !_shell->IsSetup()) { + return; + } - _platformView = std::make_shared(self.renderSurface); - _platformView->Attach(); - _platformView->SetupResourceContextOnIOThread(); - _platformView->NotifyCreated(std::make_unique(_platformView.get())); + // Tell the platform view that it has a GL surface. + _shell->GetPlatformView()->NotifyCreated(); } -// TODO(eseidel): This does not belong in flutter_window! -// Probably belongs in NSApplicationDelegate didFinishLaunching. -- (void)setupAndLoadDart { - _platformView->SetupAndLoadDart(); +- (void)notifySurfaceDestroyed { + if (!_shell || !_shell->IsSetup()) { + return; + } + + // Tell the platform view that its surface is about to be lost. + _shell->GetPlatformView()->NotifyDestroyed(); } - (void)windowDidResize:(NSNotification*)notification { @@ -72,34 +177,28 @@ static inline blink::PointerData::Change PointerChangeFromNSEventPhase(NSEventPh } - (void)updateWindowSize { - [self setupSurfaceIfNecessary]; + if (!_shell) { + return; + } blink::ViewportMetrics metrics; auto size = self.renderSurface.frame.size; metrics.physical_width = size.width; metrics.physical_height = size.height; - - blink::Threads::UI()->PostTask([ engine = _platformView->engine().GetWeakPtr(), metrics ] { - if (engine.get()) { + _shell->GetTaskRunners().GetUITaskRunner()->PostTask([engine = _shell->GetEngine(), metrics]() { + if (engine) { engine->SetViewportMetrics(metrics); } }); } -- (void)setupSurfaceIfNecessary { - if (self.isSurfaceSetup) { - return; - } - - self.surfaceSetup = YES; - - [self setupPlatformView]; - [self setupAndLoadDart]; -} - #pragma mark - Responder overrides - (void)dispatchEvent:(NSEvent*)event phase:(NSEventPhase)phase { + if (!_shell) { + return; + } + NSPoint location = [_renderSurface convertPoint:event.locationInWindow fromView:nil]; location.y = _renderSurface.frame.size.height - location.y; @@ -134,13 +233,14 @@ static inline blink::PointerData::Change PointerChangeFromNSEventPhase(NSEventPh break; } - 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); - } - }); + _shell->GetTaskRunners().GetUITaskRunner()->PostTask( + [engine = _shell->GetEngine(), pointer_data] { + if (engine) { + blink::PointerDataPacket packet(1); + packet.SetPointerData(0, pointer_data); + engine->DispatchPointerDataPacket(packet); + } + }); } - (void)mouseDown:(NSEvent*)event { @@ -155,11 +255,18 @@ static inline blink::PointerData::Change PointerChangeFromNSEventPhase(NSEventPh [self dispatchEvent:event phase:NSEventPhaseEnded]; } -- (void)dealloc { - if (_platformView) { - _platformView->NotifyDestroyed(); - } +- (void)reset { + [self notifySurfaceDestroyed]; + _shell.reset(); + _thread_host.Reset(); +} +- (void)windowWillClose:(NSNotification*)notification { + [self reset]; +} + +- (void)dealloc { + [self reset]; [super dealloc]; } diff --git a/shell/platform/darwin/desktop/main_mac.mm b/shell/platform/darwin/desktop/main_mac.mm index 808a5f63f1d145ac2fb4d731f77c5c971deddee6..edd08d0c8b7838396d2dae63d6a2ed7c64819967 100644 --- a/shell/platform/darwin/desktop/main_mac.mm +++ b/shell/platform/darwin/desktop/main_mac.mm @@ -7,91 +7,20 @@ #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/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 "flutter/shell/platform/darwin/desktop/flutter_application_delegate.h" #include "lib/fxl/command_line.h" #include "lib/fxl/logging.h" -#include "lib/tonic/dart_microtask_queue.h" -// 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() { +int main(int argc, const char* argv[]) { 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()); -} - -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); + auto command_line = fxl::CommandLineFromIterators(args_vector.begin(), args_vector.end()); // Print help. if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) { @@ -99,36 +28,7 @@ int main(int argc, const char* argv[]) { return EXIT_SUCCESS; } - // 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); - } + [NSApplication sharedApplication].delegate = + [[[FlutterApplicationDelegate alloc] init] autorelease]; + 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 501400b6803d46a362444e8b0d002573116dff64..d4b19b94d1d99ee33cd9dce66b70b63f39326968 100644 --- a/shell/platform/darwin/desktop/platform_view_mac.h +++ b/shell/platform/darwin/desktop/platform_view_mac.h @@ -7,6 +7,7 @@ #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" @@ -15,15 +16,13 @@ namespace shell { -class PlatformViewMac : public PlatformView, public GPUSurfaceGLDelegate { +class PlatformViewMac final : public PlatformView, public GPUSurfaceGLDelegate { public: - PlatformViewMac(NSOpenGLView* gl_view); + PlatformViewMac(Shell& shell, NSOpenGLView* gl_view); ~PlatformViewMac() override; - virtual void Attach() override; - - void SetupAndLoadDart(); + std::unique_ptr CreateVSyncWaiter() override; bool GLContextMakeCurrent() override; @@ -33,27 +32,17 @@ class PlatformViewMac : 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; - void SetupAndLoadFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages); + // |shell::PlatformView| + std::unique_ptr CreateRenderingSurface() override; - void SetAssetBundlePathOnUI(const std::string& assets_directory); + // |shell::PlatformView| + sk_sp CreateResourceContext() const override; 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 42948386fbcd420e80f2b3d1e72dcf7414233185..f25fa6945af23a9fd338912f8d512228975b5d6f 100644 --- a/shell/platform/darwin/desktop/platform_view_mac.mm +++ b/shell/platform/darwin/desktop/platform_view_mac.mm @@ -7,77 +7,26 @@ #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(NSOpenGLView* gl_view) - : PlatformView(std::make_unique(std::make_unique())), +PlatformViewMac::PlatformViewMac(Shell& shell, NSOpenGLView* gl_view) + : PlatformView(shell, shell.GetTaskRunners()), opengl_view_([gl_view retain]), resource_loading_context_([[NSOpenGLContext alloc] initWithFormat:gl_view.pixelFormat shareContext:gl_view.openGLContext]) {} PlatformViewMac::~PlatformViewMac() = default; -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); - }); +std::unique_ptr PlatformViewMac::CreateVSyncWaiter() { + return std::make_unique(task_runners_); } intptr_t PlatformViewMac::GLContextFBO() const { @@ -115,21 +64,9 @@ bool PlatformViewMac::GLContextPresent() { return true; } -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; +sk_sp PlatformViewMac::CreateResourceContext() const { + [resource_loading_context_.get() makeCurrentContext]; + return IOManager::CreateCompatibleResourceLoadingContext(GrBackend::kOpenGL_GrBackend); } bool PlatformViewMac::IsValid() const { @@ -146,30 +83,8 @@ bool PlatformViewMac::IsValid() const { return true; } -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; +std::unique_ptr PlatformViewMac::CreateRenderingSurface() { + return std::make_unique(this); } } // namespace shell diff --git a/shell/platform/darwin/desktop/vsync_waiter_mac.cc b/shell/platform/darwin/desktop/vsync_waiter_mac.cc index a28ff62edb918e5896cdfb888ca18b19062a1df8..0ccadaf42754d8d7f06b5d836778c59ea1fdabbd 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() : opaque_(nullptr) { +VsyncWaiterMac::VsyncWaiterMac(blink::TaskRunners task_runners) + : VsyncWaiter(std::move(task_runners)), opaque_(nullptr) { // Create the link. CVDisplayLinkRef link = nullptr; CVDisplayLinkCreateWithActiveCGDisplays(&link); @@ -48,18 +48,10 @@ void VsyncWaiterMac::OnDisplayLink() { CVDisplayLinkStop(link_); - 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); - }); + FireCallback(frame_start_time, frame_target_time); } -void VsyncWaiterMac::AsyncWaitForVsync(Callback callback) { - FXL_DCHECK(!callback_); - callback_ = std::move(callback); +void VsyncWaiterMac::AwaitVSync() { CVDisplayLinkStart(link_); } diff --git a/shell/platform/darwin/desktop/vsync_waiter_mac.h b/shell/platform/darwin/desktop/vsync_waiter_mac.h index 15f551f2129011ee56f999fe258a0e9d2381df0b..0ad929a509ea318471b4a493b78ae9795cdb0a1f 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 : public VsyncWaiter { +class VsyncWaiterMac final : public VsyncWaiter { public: - VsyncWaiterMac(); + VsyncWaiterMac(blink::TaskRunners task_runners); ~VsyncWaiterMac() override; - void AsyncWaitForVsync(Callback callback) override; - private: void* opaque_; - Callback callback_; + + void AwaitVSync() override; 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 310af79c2ed8e2cc34e8abe45ff4bc3836ed94b6..8946ee954c23a5da0354c9570efd4599f54b6fe2 100644 --- a/shell/platform/darwin/ios/BUILD.gn +++ b/shell/platform/darwin/ios/BUILD.gn @@ -40,8 +40,6 @@ 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", @@ -53,14 +51,15 @@ 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", @@ -86,6 +85,7 @@ 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,7 +95,10 @@ shared_library("create_flutter_framework_dylib") { "//third_party/skia", ] if (flutter_runtime_mode == "debug") { - deps += [ "//third_party/dart/runtime:libdart_jit" ] + deps += [ + "$flutter_root/lib/snapshot", + "//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 d5f30d02664d970b8a8301be173114f2202ccf5c..3c613c9fbad8f9cd851f19590538e387b75dc28c 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm @@ -2,42 +2,121 @@ // 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/threads.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/shell/common/shell.h" #include "flutter/shell/common/switches.h" -#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; +#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; + } } - return [defaults URLForKey:@(name.data())]; -} + 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; + } + } -@implementation FlutterDartProject { - NSBundle* _precompiledDartBundle; - FlutterDartSource* _dartSource; + // 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; + } + } + } - VMType _vmTypeRequirement; + // 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; + } + } + } + } + } + + return settings; } -+ (void)initialize { - if (self == [FlutterDartProject class]) { - shell::FlutterMain(); - } +@implementation FlutterDartProject { + fml::scoped_nsobject _precompiledDartBundle; + blink::Settings _settings; } #pragma mark - Override base class designated initializers @@ -52,9 +131,16 @@ static NSURL* URLForSwitch(const fxl::StringView name) { self = [super init]; if (self) { - _precompiledDartBundle = [bundle retain]; + _precompiledDartBundle.reset([bundle retain]); - [self checkReadiness]; + _settings = DefaultSettingsForProcess(); + + if (bundle != nil) { + NSString* executablePath = _precompiledDartBundle.get().executablePath; + if ([[NSFileManager defaultManager] fileExistsAtPath:executablePath]) { + _settings.application_library_path = executablePath.UTF8String; + } + } } return self; @@ -66,11 +152,15 @@ static NSURL* URLForSwitch(const fxl::StringView name) { self = [super init]; if (self) { - _dartSource = [[FlutterDartSource alloc] initWithDartMain:dartMainURL - packages:dartPackages - flutterAssets:flutterAssetsURL]; + _settings = DefaultSettingsForProcess(); - [self checkReadiness]; + 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; + } } return self; @@ -80,10 +170,17 @@ static NSURL* URLForSwitch(const fxl::StringView name) { self = [super init]; if (self) { - _dartSource = - [[FlutterDartSource alloc] initWithFlutterAssetsWithScriptSnapshot:flutterAssetsURL]; + _settings = DefaultSettingsForProcess(); - [self checkReadiness]; + 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; + } + } } return self; @@ -92,56 +189,19 @@ static NSURL* URLForSwitch(const fxl::StringView name) { #pragma mark - Convenience initializers - (instancetype)initFromDefaultSourceForConfiguration { - NSBundle* bundle = [NSBundle mainBundle]; - - if (Dart_IsPrecompiledRuntime()) { - // Load from an AOTC snapshot. - return [self initWithPrecompiledDartBundle:bundle]; + if (blink::DartVM::IsRunningPrecompiledCode()) { + return [self initWithPrecompiledDartBundle:nil]; } else { - // 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]; + return [self initWithFlutterAssets:nil dartMain:nil packages:nil]; } - - NSAssert(NO, @"Unreachable"); - [self release]; - return nil; } -#pragma mark - Common initialization tasks - -- (void)checkReadiness { - if (_precompiledDartBundle != nil) { - _vmTypeRequirement = VMTypePrecompilation; - return; - } +- (const blink::Settings&)settings { + return _settings; +} - if (_dartSource != nil) { - _vmTypeRequirement = VMTypeInterpreter; - return; - } +- (shell::RunConfiguration)runConfiguration { + return shell::RunConfiguration::InferFromSettings(_settings); } #pragma mark - Assets-related utilities @@ -161,7 +221,7 @@ static NSURL* URLForSwitch(const fxl::StringView name) { } + (NSString*)lookupKeyForAsset:(NSString*)asset { - NSString* flutterAssetsName = [FlutterDartProject flutterAssetsName: [NSBundle mainBundle]]; + NSString* flutterAssetsName = [FlutterDartProject flutterAssetsName:[NSBundle mainBundle]]; return [NSString stringWithFormat:@"%@/%@", flutterAssetsName, asset]; } @@ -169,179 +229,4 @@ static NSURL* URLForSwitch(const fxl::StringView name) { 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 75db7c4049dd918f305810fcd7846b5e733b3047..7fe1fc364f3285885ea53d4f42b32799c6f26437 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h @@ -5,32 +5,15 @@ #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 () -- (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; +- (const blink::Settings&)settings; -+ (NSString*)pathForFlutterAssetsFromBundle:(NSBundle*)bundle; +- (shell::RunConfiguration)runConfiguration; @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h b/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h deleted file mode 100644 index c3881ce06518521565db7ae176db0e8d0862195c..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartSource.h +++ /dev/null @@ -1,30 +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. - -#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 deleted file mode 100644 index aecb4e5806b3a9dc181a1a2f5d7af1d60a2b1739..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/ios/framework/Source/FlutterDartSource.mm +++ /dev/null @@ -1,100 +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. - -#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 2143f362f79051dbefa0e3ed5d98ed9e7af3ffa1..dee11d08934a5b75aa11574deb2a8ec9e146dbc1 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterHeadlessDartRunner.mm @@ -2,38 +2,84 @@ // 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/platform/darwin/scoped_nsobject.h" -#include "flutter/shell/common/null_platform_view.h" -#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterDartProject_Internal.h" +#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" -@interface FlutterHeadlessDartRunner () -@end +static std::unique_ptr CreateHeadlessPlatformView(shell::Shell& shell) { + return std::make_unique(shell, shell.GetTaskRunners()); +} -@implementation FlutterHeadlessDartRunner { - fml::scoped_nsprotocol _dartProject; - std::shared_ptr _platformView; +static std::unique_ptr CreateHeadlessRasterizer(shell::Shell& shell) { + return std::make_unique(shell.GetTaskRunners()); } -- (instancetype)init { - _dartProject.reset([[FlutterDartProject alloc] initFromDefaultSourceForConfiguration]); - _platformView = std::make_shared(); - _platformView->Attach(); - return self; +@implementation FlutterHeadlessDartRunner { + shell::ThreadHost _threadHost; + std::unique_ptr _shell; } - (void)runWithEntrypoint:(NSString*)entrypoint { - 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); - }]; + 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."; + } + })); } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterView.h b/shell/platform/darwin/ios/framework/Source/FlutterView.h index 661940620c947ddfb9e5d12d444a0003dd7ae8dc..5e3d303401725bf61dd1d6bf06b1991d001ee665 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.h @@ -7,8 +7,14 @@ #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 7c382838c6f5ce77c0ef0125830d1f7c5872ad07..27e3d48c4cb50c3509cd840519797f0c94d5f266 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterView.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterView.mm @@ -5,20 +5,41 @@ #include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/common/settings.h" -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.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); @@ -40,13 +61,24 @@ #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; } -void SnapshotRasterizer(fml::WeakPtr rasterizer, - CGContextRef context, - bool is_opaque) { +static void SnapshotRasterizer(fml::WeakPtr rasterizer, + CGContextRef context, + bool is_opaque) { if (!rasterizer) { return; } @@ -77,10 +109,11 @@ void SnapshotRasterizer(fml::WeakPtr rasterizer, SkCanvas canvas(bitmap); - { - flow::CompositorContext compositor_context(nullptr); - auto frame = compositor_context.AcquireFrame(nullptr, &canvas, false /* instrumentation */); - layer_tree->Raster(frame, false /* ignore raster cache. */); + 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); } canvas.flush(); @@ -89,41 +122,6 @@ 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 @@ -132,7 +130,22 @@ void SnapshotContentsSync(CGContextRef context, UIView* view) { // 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 { - SnapshotContentsSync(context, self); + 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(); } @end diff --git a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm index a467a5a8cf1a5b33b9572eddac26ed16cec465fd..17e9a4eff48f6a079d418e382df59c3ec4b2dd2f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController.mm @@ -2,90 +2,54 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h" +#define FML_USED_ON_EMBEDDER + +#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h" #include -#include "flutter/common/threads.h" -#include "flutter/flow/texture.h" +#include "flutter/fml/message_loop.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/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/common/thread_host.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/flutter_main_ios.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/FlutterView.h" #include "flutter/shell/platform/darwin/ios/framework/Source/flutter_touch_mapper.h" -#include "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h" +#include "flutter/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.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) {} - fml::ScopedBlock callback_; -}; - -} // namespace - -@interface FlutterViewController () +@interface FlutterViewController () @end @implementation FlutterViewController { - fml::scoped_nsprotocol _dartProject; + 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; 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 @@ -125,26 +89,92 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { _orientationPreferences = UIInterfaceOrientationMaskAll; _statusBarStyle = UIStatusBarStyleDefault; - _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(); - }]; + + 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->SetupResourceContextOnIOThread(); + })); + return true; +} +- (void)setupChannels { _localizationChannel.reset([[FlutterMethodChannel alloc] initWithName:@"flutter/localization" binaryMessenger:self @@ -190,9 +220,8 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { [_textInputChannel.get() setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) { [_textInputPlugin.get() handleMethodCall:call result:result]; }]; - _platformView->SetTextInputPlugin(_textInputPlugin); - - [self setupNotificationCenterObservers]; + static_cast(_shell->GetPlatformView().get()) + ->SetTextInputPlugin(_textInputPlugin); } - (void)setupNotificationCenterObservers { @@ -261,50 +290,24 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { - (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 { - FlutterView* view = [[FlutterView alloc] init]; - - self.view = view; + self.view = _flutterView.get(); self.view.multipleTouchEnabled = YES; self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - [view release]; + [self installLaunchViewIfNecessary]; +} + +#pragma mark - Managing launch views +- (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) { @@ -319,16 +322,57 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { } } +- (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) { - _platformView->NotifyCreated(); + [self installLaunchViewCallback]; + _shell->GetPlatformView()->NotifyCreated(); + } else { - _platformView->NotifyDestroyed(); + _shell->GetPlatformView()->NotifyDestroyed(); } } @@ -336,7 +380,6 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { - (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) @@ -391,8 +434,6 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { - (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"]; } @@ -400,7 +441,6 @@ class PlatformMessageResponseDarwin : public blink::PlatformMessageResponse { TRACE_EVENT0("flutter", "applicationWillEnterForeground"); if (_viewportMetrics.physical_width) [self surfaceUpdated:YES]; - blink::ResourceContext::Unfreeze(); [_lifecycleChannel.get() sendMessage:@"AppLifecycleState.inactive"]; } @@ -547,10 +587,11 @@ static inline blink::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* to packet->SetPointerData(i++, pointer_data); } - blink::Threads::UI()->PostTask(fxl::MakeCopyable( - [ engine = _platformView->engine().GetWeakPtr(), packet = std::move(packet) ] { - if (engine.get()) + _shell->GetTaskRunners().GetUITaskRunner()->PostTask( + fxl::MakeCopyable([engine = _shell->GetEngine(), packet = std::move(packet)] { + if (engine) { engine->DispatchPointerDataPacket(*packet); + } })); } @@ -573,13 +614,11 @@ static inline blink::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* to #pragma mark - Handle view resizing - (void)updateViewportMetrics { - blink::Threads::UI()->PostTask( - [ weak_platform_view = _platformView->GetWeakPtr(), metrics = _viewportMetrics ] { - if (!weak_platform_view) { - return; + _shell->GetTaskRunners().GetUITaskRunner()->PostTask( + [engine = _shell->GetEngine(), metrics = _viewportMetrics]() { + if (engine) { + engine->SetViewportMetrics(std::move(metrics)); } - weak_platform_view->UpdateSurfaceSize(); - weak_platform_view->engine().SetViewportMetrics(metrics); }); } @@ -709,7 +748,7 @@ static inline blink::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* to #else bool enabled = UIAccessibilityIsVoiceOverRunning(); #endif - _platformView->ToggleAccessibility(self.view, enabled); + _shell->GetPlatformView()->SetSemanticsEnabled(enabled); } #pragma mark - Memory Notifications @@ -875,46 +914,50 @@ constexpr CGFloat kStandardStatusBarHeight = 20.0; 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); - }); + : fxl::MakeRefCounted( + ^(NSData* reply) { + callback(reply); + }, + _shell->GetTaskRunners().GetPlatformTaskRunner()); fxl::RefPtr platformMessage = (message == nil) ? fxl::MakeRefCounted(channel.UTF8String, response) : fxl::MakeRefCounted( channel.UTF8String, shell::GetVectorFromNSData(message), response); - _platformView->DispatchPlatformMessage(platformMessage); + + _shell->GetPlatformView()->DispatchPlatformMessage(platformMessage); } - (void)setMessageHandlerOnChannel:(NSString*)channel binaryMessageHandler:(FlutterBinaryMessageHandler)handler { NSAssert(channel, @"The channel must not be null"); - _platformView->platform_message_router().SetMessageHandler(channel.UTF8String, handler); + [self iosPlatformView] -> GetPlatformMessageRouter().SetMessageHandler(channel.UTF8String, + handler); } #pragma mark - FlutterTextureRegistry - (int64_t)registerTexture:(NSObject*)texture { int64_t textureId = _nextTextureId++; - _platformView->RegisterExternalTexture(textureId, texture); + [self iosPlatformView] -> RegisterExternalTexture(textureId, texture); return textureId; } - (void)unregisterTexture:(int64_t)textureId { - _platformView->UnregisterTexture(textureId); + _shell->GetPlatformView()->UnregisterTexture(textureId); } - (void)textureFrameAvailable:(int64_t)textureId { - _platformView->MarkTextureFrameAvailable(textureId); + _shell->GetPlatformView()->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 new file mode 100644 index 0000000000000000000000000000000000000000..482379c8f17eb75c86fdff9d912309dfec39d71f --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h @@ -0,0 +1,17 @@ +// 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 3f96f37a9c2dbcd716ae3142adffd71efffc3ed4..6a545b95e4276c86d9467d033c7acc72822a800b 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 @@ AccessibilityBridge::AccessibilityBridge(UIView* view, PlatformViewIOS* platform weak_factory_(this) { accessibility_channel_.reset([[FlutterBasicMessageChannel alloc] initWithName:@"flutter/accessibility" - binaryMessenger:platform_view->binary_messenger() + binaryMessenger:platform_view->GetOwnerViewController() codec:[FlutterStandardMessageCodec sharedInstance]]); [accessibility_channel_.get() setMessageHandler:^(id message, FlutterReply reply) { HandleEvent((NSDictionary*)message); @@ -440,7 +440,7 @@ AccessibilityBridge::~AccessibilityBridge() { } UIView* AccessibilityBridge::textInputView() { - return [platform_view_->text_input_plugin() textInputView]; + return [platform_view_->GetTextInputPlugin() 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 deleted file mode 100644 index f2e54dd2c2806592a6465c83ca3c3b02ef81d039..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/ios/framework/Source/flutter_main_ios.h +++ /dev/null @@ -1,18 +0,0 @@ -// 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 deleted file mode 100644 index aa7ad5fd857276136b423204be72e2f33681d2bb..0000000000000000000000000000000000000000 --- a/shell/platform/darwin/ios/framework/Source/flutter_main_ios.mm +++ /dev/null @@ -1,25 +0,0 @@ -// 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 new file mode 100644 index 0000000000000000000000000000000000000000..b861c5036e97de52560a8649fac5690ec04711d7 --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.h @@ -0,0 +1,50 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..8590b4e36942bbb7efd36d935ebc3b783ee75acd --- /dev/null +++ b/shell/platform/darwin/ios/framework/Source/platform_message_response_darwin.mm @@ -0,0 +1,11 @@ +// 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 cfa91c04771c3a529cd49b66c03768a4936e19aa..d2488f82fe47c7ff89b383746863e32ffdb9d12d 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_message_router.h +++ b/shell/platform/darwin/ios/framework/Source/platform_message_router.h @@ -7,6 +7,7 @@ #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" @@ -18,13 +19,13 @@ class PlatformMessageRouter { PlatformMessageRouter(); ~PlatformMessageRouter(); - void HandlePlatformMessage(fxl::RefPtr message); + void HandlePlatformMessage(fxl::RefPtr message) const; 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 70625143b623ef55a734a9b1388cc8d8664d57b4..3ab75bff522f8b52ac279edd9252c6a598e16552 100644 --- a/shell/platform/darwin/ios/framework/Source/platform_message_router.mm +++ b/shell/platform/darwin/ios/framework/Source/platform_message_router.mm @@ -14,7 +14,8 @@ PlatformMessageRouter::PlatformMessageRouter() = default; PlatformMessageRouter::~PlatformMessageRouter() = default; -void PlatformMessageRouter::HandlePlatformMessage(fxl::RefPtr message) { +void PlatformMessageRouter::HandlePlatformMessage( + fxl::RefPtr message) const { fxl::RefPtr completer = message->response(); auto it = message_handlers_.find(message->channel()); if (it != message_handlers_.end()) { @@ -41,14 +42,10 @@ void PlatformMessageRouter::HandlePlatformMessage(fxl::RefPtrsecond release]; - message_handlers_.erase(it); - } + message_handlers_.erase(channel); + if (handler) { + message_handlers_[channel] = + fml::ScopedBlock{handler, fml::OwnershipPolicy::Retain}; } } 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 6a3362b2156679e3f2ff5de35ae36b3160e4aefa..23aaf02510d6dfbc631802b1f987bbf42bec32d1 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.h @@ -5,27 +5,26 @@ #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 : public VsyncWaiter { +class VsyncWaiterIOS final : public VsyncWaiter { public: - VsyncWaiterIOS(); - ~VsyncWaiterIOS() override; + VsyncWaiterIOS(blink::TaskRunners task_runners); - void AsyncWaitForVsync(Callback callback) override; + ~VsyncWaiterIOS() override; private: - Callback callback_; - VSyncClient* client_; + fml::scoped_nsobject client_; + + // |shell::VsyncWaiter| + void AwaitVSync() override; 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 78d667818912311b27340e6ce49cbfcb98f79f06..4589368acd3fb75f13a3f2065ad0c3f851125c34 100644 --- a/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm +++ b/shell/platform/darwin/ios/framework/Source/vsync_waiter_ios.mm @@ -10,29 +10,62 @@ #include #include -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.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 { - CADisplayLink* _displayLink; - shell::VsyncWaiter::Callback _pendingCallback; + shell::VsyncWaiter::Callback callback_; + fml::scoped_nsobject display_link_; } -- (instancetype)init { +- (instancetype)initWithTaskRunner:(fxl::RefPtr)task_runner + callback:(shell::VsyncWaiter::Callback)callback { self = [super init]; if (self) { - _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]; + 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]; [client release]; }); } @@ -40,68 +73,28 @@ return self; } -- (void)await:(shell::VsyncWaiter::Callback)callback { - FXL_DCHECK(!_pendingCallback); - _pendingCallback = std::move(callback); - _displayLink.paused = NO; +- (void)await { + display_link_.get().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); - _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; + display_link_.get().paused = YES; + + callback_(frame_start_time, frame_target_time); +} + +- (void)invalidate { + // [CADisplayLink invalidate] is thread-safe. + [display_link_.get() invalidate]; } - (void)dealloc { - [_displayLink invalidate]; - [_displayLink release]; + [self invalidate]; [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 a658fdf31628a301281a85edcea0172ac433d7a5..baedf298bd61d768ec2b942044c032a967e56e18 100644 --- a/shell/platform/darwin/ios/ios_external_texture_gl.h +++ b/shell/platform/darwin/ios/ios_external_texture_gl.h @@ -25,6 +25,8 @@ 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 2cc9721e7f09ac9f87d154984fed7b3a8023e7bf..0bd9a8ca3c7cb3dd3f9c1e6f77ffdec9df06446c 100644 --- a/shell/platform/darwin/ios/ios_external_texture_gl.mm +++ b/shell/platform/darwin/ios/ios_external_texture_gl.mm @@ -4,11 +4,10 @@ #include "flutter/shell/platform/darwin/ios/ios_external_texture_gl.h" -#include +#import #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" @@ -26,7 +25,6 @@ IOSExternalTextureGL::IOSExternalTextureGL(int64_t textureId, 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, @@ -57,10 +55,8 @@ void IOSExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds) { 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); @@ -69,14 +65,13 @@ void IOSExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds) { } } -void IOSExternalTextureGL::OnGrContextCreated() { - ASSERT_IS_GPU_THREAD -} +void IOSExternalTextureGL::OnGrContextCreated() {} 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 89ad7e0347eac8cd7e704020c8fd821303dfbb48..f42c1436461b1b0d75d0a80bd3eb0386bb6fa25f 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(PlatformView::SurfaceConfig config, CAEAGLLayer* layer); + IOSGLContext(fml::scoped_nsobject layer); ~IOSGLContext(); diff --git a/shell/platform/darwin/ios/ios_gl_context.mm b/shell/platform/darwin/ios/ios_gl_context.mm index de94018d0689e73c9255c1cdcd3e33efb46608de..77a124e64a2911d6b84befbccbadb5a19e55e52e 100644 --- a/shell/platform/darwin/ios/ios_gl_context.mm +++ b/shell/platform/darwin/ios/ios_gl_context.mm @@ -3,21 +3,17 @@ // found in the LICENSE file. #include "flutter/shell/platform/darwin/ios/ios_gl_context.h" -#include "third_party/skia/include/gpu/GrContextOptions.h" -#include "third_party/skia/include/gpu/gl/GrGLInterface.h" #include -namespace shell { +#include "flutter/fml/trace_event.h" +#include "third_party/skia/include/gpu/GrContextOptions.h" +#include "third_party/skia/include/gpu/gl/GrGLInterface.h" -#define VERIFY(x) \ - if (!(x)) { \ - FXL_DLOG(ERROR) << "Failed: " #x; \ - return; \ - }; +namespace shell { -IOSGLContext::IOSGLContext(PlatformView::SurfaceConfig config, CAEAGLLayer* layer) - : layer_([layer retain]), +IOSGLContext::IOSGLContext(fml::scoped_nsobject layer) + : layer_(std::move(layer)), context_([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]), resource_context_([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2 sharegroup:context_.get().sharegroup]), @@ -26,34 +22,34 @@ IOSGLContext::IOSGLContext(PlatformView::SurfaceConfig config, CAEAGLLayer* laye storage_size_width_(0), storage_size_height_(0), valid_(false) { - VERIFY(layer_ != nullptr); - VERIFY(context_ != nullptr); - VERIFY(resource_context_ != nullptr); + FXL_DCHECK(layer_ != nullptr); + FXL_DCHECK(context_ != nullptr); + FXL_DCHECK(resource_context_ != nullptr); bool context_current = [EAGLContext setCurrentContext:context_]; - VERIFY(context_current); - VERIFY(glGetError() == GL_NO_ERROR); + FXL_DCHECK(context_current); + FXL_DCHECK(glGetError() == GL_NO_ERROR); // Generate the framebuffer glGenFramebuffers(1, &framebuffer_); - VERIFY(glGetError() == GL_NO_ERROR); - VERIFY(framebuffer_ != GL_NONE); + FXL_DCHECK(glGetError() == GL_NO_ERROR); + FXL_DCHECK(framebuffer_ != GL_NONE); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer_); - VERIFY(glGetError() == GL_NO_ERROR); + FXL_DCHECK(glGetError() == GL_NO_ERROR); // Setup color attachment glGenRenderbuffers(1, &colorbuffer_); - VERIFY(colorbuffer_ != GL_NONE); + FXL_DCHECK(colorbuffer_ != GL_NONE); glBindRenderbuffer(GL_RENDERBUFFER, colorbuffer_); - VERIFY(glGetError() == GL_NO_ERROR); + FXL_DCHECK(glGetError() == GL_NO_ERROR); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer_); - VERIFY(glGetError() == GL_NO_ERROR); + FXL_DCHECK(glGetError() == GL_NO_ERROR); // TODO: // iOS displays are more variable than just P3 or sRGB. Reading the display @@ -139,24 +135,12 @@ bool IOSGLContext::UpdateStorageSizeIfNecessary() { return false; } - GLint width = 0; - GLint height = 0; - - 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); - } + // 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); - storage_size_width_ = width; - storage_size_height_ = height; + glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &storage_size_height_); + FXL_DCHECK(glGetError() == GL_NO_ERROR); 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 c164fab15500ef1b42ac474d751a205cd62c8757..b629c2709e3d1d77d1473793bc325fd156ba10c6 100644 --- a/shell/platform/darwin/ios/ios_surface.h +++ b/shell/platform/darwin/ios/ios_surface.h @@ -5,25 +5,17 @@ #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/platform_view.h" +#include "flutter/shell/common/surface.h" #include "lib/fxl/macros.h" -@class CALayer; - namespace shell { class IOSSurface { public: - 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; + IOSSurface(); virtual ~IOSSurface(); @@ -36,9 +28,6 @@ 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 91067838330f6e85556879150e34167d3f93d98e..b0b9cc324518370f1cfe010ba895476a5c72649b 100644 --- a/shell/platform/darwin/ios/ios_surface.mm +++ b/shell/platform/darwin/ios/ios_surface.mm @@ -4,40 +4,15 @@ #include "flutter/shell/platform/darwin/ios/ios_surface.h" -#include -#include #include -@class CALayer; -@class CAEAGLLayer; +#include +#include namespace shell { -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; 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 f7e43e25889842e5d43c7caf5fa48a6f04779411..7486d343eb0fd26f32feb004d8fb8957d7c9e4d3 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.h +++ b/shell/platform/darwin/ios/ios_surface_gl.h @@ -5,6 +5,7 @@ #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" @@ -16,7 +17,7 @@ namespace shell { class IOSSurfaceGL : public IOSSurface, public GPUSurfaceGLDelegate { public: - IOSSurfaceGL(PlatformView::SurfaceConfig surface_config, CAEAGLLayer* layer); + IOSSurfaceGL(fml::scoped_nsobject layer); ~IOSSurfaceGL() override; diff --git a/shell/platform/darwin/ios/ios_surface_gl.mm b/shell/platform/darwin/ios/ios_surface_gl.mm index 60756d6094fc93cd5c5ba7d8064dcf469c11be84..253531c4800aa81c3bf9e4d5567afb853559218a 100644 --- a/shell/platform/darwin/ios/ios_surface_gl.mm +++ b/shell/platform/darwin/ios/ios_surface_gl.mm @@ -4,13 +4,12 @@ #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(PlatformView::SurfaceConfig surface_config, CAEAGLLayer* layer) - : IOSSurface(surface_config, reinterpret_cast(layer)), - context_(surface_config, layer) {} +IOSSurfaceGL::IOSSurfaceGL(fml::scoped_nsobject layer) : context_(std::move(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 7e3f264b28ce6ba8adecd9bd0d6bffa6c8b87cf7..e8fc332f06c8c36899af9a3b9cb7153165676429 100644 --- a/shell/platform/darwin/ios/ios_surface_software.h +++ b/shell/platform/darwin/ios/ios_surface_software.h @@ -5,17 +5,19 @@ #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 : public IOSSurface, - public GPUSurfaceSoftwareDelegate { +class IOSSurfaceSoftware final : public IOSSurface, + public GPUSurfaceSoftwareDelegate { public: - IOSSurfaceSoftware(PlatformView::SurfaceConfig surface_config, - CALayer* layer); + IOSSurfaceSoftware(fml::scoped_nsobject layer); ~IOSSurfaceSoftware() override; @@ -32,6 +34,7 @@ class IOSSurfaceSoftware : 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 9a4e90e45dfbac37df30ed13ff146700265f5fa9..b09a5d9a2d8a3fb346f000dd834071658476c03e 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(PlatformView::SurfaceConfig surface_config, CALayer* layer) - : IOSSurface(surface_config, layer) { +IOSSurfaceSoftware::IOSSurfaceSoftware(fml::scoped_nsobject layer) + : layer_(std::move(layer)) { UpdateStorageSizeIfNecessary(); } IOSSurfaceSoftware::~IOSSurfaceSoftware() = default; bool IOSSurfaceSoftware::IsValid() const { - return GetLayer() != nullptr; + return layer_; } bool IOSSurfaceSoftware::ResourceContextMakeCurrent() { @@ -120,8 +120,7 @@ bool IOSSurfaceSoftware::PresentBackingStore(sk_sp backing_store) { return false; } - CALayer* layer = GetLayer(); - layer.contents = reinterpret_cast(static_cast(pixmap_image)); + layer_.get().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 dab19a0f9ce1a7fec01418a038f10d566d51810e..e7849dda44641737860e1c246ad720639c7048f0 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -8,95 +8,66 @@ #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/Source/FlutterTextInputPlugin.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/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 : public PlatformView { +class PlatformViewIOS final : public PlatformView { public: - explicit PlatformViewIOS(CALayer* layer, - NSObject* binaryMessenger); + explicit PlatformViewIOS(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + FlutterViewController* owner_controller_, + FlutterView* owner_view_); ~PlatformViewIOS() override; - void Attach() override; - - void Attach(fxl::Closure firstFrameCallback); - - void NotifyCreated(); - - void ToggleAccessibility(UIView* view, bool enabled); - - PlatformMessageRouter& platform_message_router() { - return platform_message_router_; - } - - fml::WeakPtr GetWeakPtr(); - - void UpdateSurfaceSize(); + PlatformMessageRouter& GetPlatformMessageRouter(); - VsyncWaiter* GetVsyncWaiter() override; - - bool ResourceContextMakeCurrent() override; - - void HandlePlatformMessage( - fxl::RefPtr message) override; + FlutterViewController* GetOwnerViewController() const; void RegisterExternalTexture(int64_t id, NSObject* texture); - void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - - void RunFromSource(const std::string& assets_directory, - const std::string& main, - const std::string& packages) override; + fml::scoped_nsprotocol GetTextInputPlugin() const; - 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_; - } + fml::scoped_nsprotocol plugin); 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_; - fxl::Closure firstFrameCallback_; - fml::WeakPtrFactory weak_factory_; - NSObject* binary_messenger_; fml::scoped_nsprotocol text_input_plugin_; + fxl::Closure firstFrameCallback_; + + // |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; + + // |shell::PlatformView| + void SetSemanticsEnabled(bool enabled) override; + + // |shell::PlatformView| + void HandlePlatformMessage( + fxl::RefPtr message) override; + + // |shell::PlatformView| + void UpdateSemantics(blink::SemanticsNodeUpdates update) override; - void SetAssetBundlePathOnUI(const std::string& assets_directory); + // |shell::PlatformView| + std::unique_ptr CreateVSyncWaiter() override; 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 19c5dd4e663a1503e7bd1084365c3bdc04476786..1fba8e5e026e58ccfb70b424687a90d963eaaa7f 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -8,135 +8,92 @@ #include -#include "flutter/common/threads.h" +#include "flutter/common/task_runners.h" #include "flutter/fml/trace_event.h" -#include "flutter/shell/gpu/gpu_rasterizer.h" -#include "flutter/shell/platform/darwin/common/process_info_mac.h" +#include "flutter/shell/common/io_manager.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(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; - -void PlatformViewIOS::Attach() { - Attach(NULL); +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); } -void PlatformViewIOS::Attach(fxl::Closure firstFrameCallback) { - CreateEngine(); - - if (firstFrameCallback) { - firstFrameCallback_ = firstFrameCallback; - rasterizer_->AddNextFrameCallback([weakSelf = GetWeakPtr()] { - if (weakSelf) { - weakSelf->firstFrameCallback_(); - weakSelf->firstFrameCallback_ = nullptr; - } - }); - } -} +PlatformViewIOS::~PlatformViewIOS() = default; -void PlatformViewIOS::NotifyCreated() { - PlatformView::NotifyCreated(ios_surface_->CreateGPUSurface()); +FlutterViewController* PlatformViewIOS::GetOwnerViewController() const { + return owner_controller_; } -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); +PlatformMessageRouter& PlatformViewIOS::GetPlatformMessageRouter() { + return platform_message_router_; } -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); - }); +void PlatformViewIOS::RegisterExternalTexture(int64_t texture_id, + NSObject* texture) { + RegisterTexture(std::make_shared(texture_id, texture)); } -void PlatformViewIOS::SetAssetBundlePathOnUI(const std::string& assets_directory) { - blink::Threads::UI()->PostTask([ engine = engine().GetWeakPtr(), assets_directory ] { - if (engine) - engine->SetAssetBundlePath(assets_directory); - }); +// |shell::PlatformView| +std::unique_ptr PlatformViewIOS::CreateRenderingSurface() { + return ios_surface_->CreateGPUSurface(); } -fml::WeakPtr PlatformViewIOS::GetWeakPtr() { - return weak_factory_.GetWeakPtr(); -} +// |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::UpdateSurfaceSize() { - blink::Threads::Gpu()->PostTask([self = GetWeakPtr()]() { - if (self && self->ios_surface_ != nullptr) { - self->ios_surface_->UpdateStorageSizeIfNecessary(); - } - }); + return IOManager::CreateCompatibleResourceLoadingContext(GrBackend::kOpenGL_GrBackend); } -VsyncWaiter* PlatformViewIOS::GetVsyncWaiter() { - if (!vsync_waiter_) { - vsync_waiter_ = std::make_unique(); +// |shell::PlatformView| +void PlatformViewIOS::SetSemanticsEnabled(bool enabled) { + if (enabled && !accessibility_bridge_) { + accessibility_bridge_ = std::make_unique(owner_view_, this); + } else { + accessibility_bridge_.reset(); } - return vsync_waiter_.get(); -} - -bool PlatformViewIOS::ResourceContextMakeCurrent() { - return ios_surface_ != nullptr ? ios_surface_->ResourceContextMakeCurrent() : false; + PlatformView::SetSemanticsEnabled(enabled); } +// |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)); } -void PlatformViewIOS::RegisterExternalTexture(int64_t texture_id, - NSObject* texture) { - RegisterTexture(std::make_shared(texture_id, texture)); +// |shell::PlatformView| +std::unique_ptr PlatformViewIOS::CreateVSyncWaiter() { + return std::make_unique(task_runners_); } -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; +fml::scoped_nsprotocol PlatformViewIOS::GetTextInputPlugin() const { + return text_input_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; +void PlatformViewIOS::SetTextInputPlugin(fml::scoped_nsprotocol plugin) { + text_input_plugin_ = plugin; } } // namespace shell diff --git a/shell/platform/embedder/BUILD.gn b/shell/platform/embedder/BUILD.gn index 7ce6f7e8d5be108dc45d220a9c21703bce3944aa..b1e0b3e4f3b7141612811db7f45d0e470140db9a 100644 --- a/shell/platform/embedder/BUILD.gn +++ b/shell/platform/embedder/BUILD.gn @@ -4,16 +4,21 @@ import("$flutter_root/testing/testing.gni") -source_set("embedder") { +static_library("embedder") { + complete_static_lib = true + 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", @@ -22,6 +27,7 @@ source_set("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 866413cbc077b1f8aafb1d7bc4cc2e792b9e8aac..a7ee807934663acac9d9564d39ee8f96137a911b 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -2,14 +2,30 @@ // 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/common/threads.h" + +#include "flutter/assets/directory_asset_bundle.h" +#include "flutter/common/task_runners.h" +#include "flutter/fml/file.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) \ @@ -41,21 +57,6 @@ 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; }; @@ -65,6 +66,7 @@ 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; } @@ -87,51 +89,44 @@ 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; @@ -147,18 +142,33 @@ FlutterResult FlutterEngineRun(size_t version, SAFE_ACCESS(args, command_line_argv, nullptr)); } - 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 = { + 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 = { .gl_make_current_callback = make_current, .gl_clear_current_callback = clear_current, .gl_present_callback = present, @@ -167,31 +177,55 @@ FlutterResult FlutterEngineRun(size_t version, .gl_make_resource_current_callback = make_resource_current_callback, }; - 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))); + 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))); + 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; } @@ -199,7 +233,9 @@ FlutterResult FlutterEngineShutdown(FlutterEngine engine) { if (engine == nullptr) { return kInvalidArguments; } - delete reinterpret_cast(engine); + auto embedder_engine = reinterpret_cast(engine); + embedder_engine->NotifyDestroyed(); + delete embedder_engine; return kSuccess; } @@ -210,21 +246,16 @@ 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); - blink::Threads::UI()->PostTask( - [ weak_engine = holder->view()->engine().GetWeakPtr(), metrics ] { - if (auto engine = weak_engine) { - engine->SetViewportMetrics(metrics); - } - }); - return kSuccess; + return reinterpret_cast(engine)->SetViewportMetrics( + std::move(metrics)) + ? kSuccess + : kInvalidArguments; } inline blink::PointerData::Change ToPointerDataChange( @@ -267,19 +298,10 @@ FlutterResult FlutterEngineSendPointerEvent(FlutterEngine engine, reinterpret_cast(current) + current->struct_size); } - 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; + return reinterpret_cast(engine) + ->DispatchPointerDataPacket(std::move(packet)) + ? kSuccess + : kInvalidArguments; } FlutterResult FlutterEngineSendPlatformMessage( @@ -294,8 +316,6 @@ FlutterResult FlutterEngineSendPlatformMessage( return kInvalidArguments; } - auto holder = reinterpret_cast(engine); - auto message = fxl::MakeRefCounted( flutter_message->channel, std::vector( @@ -303,13 +323,10 @@ FlutterResult FlutterEngineSendPlatformMessage( flutter_message->message + flutter_message->message_size), nullptr); - blink::Threads::UI()->PostTask( - [ weak_engine = holder->view()->engine().GetWeakPtr(), message ] { - if (auto engine = weak_engine) { - engine->DispatchPlatformMessage(message); - } - }); - return kSuccess; + return reinterpret_cast(engine)->SendPlatformMessage( + std::move(message)) + ? kSuccess + : kInvalidArguments; } FlutterResult FlutterEngineSendPlatformMessageResponse( diff --git a/shell/platform/embedder/embedder_engine.cc b/shell/platform/embedder/embedder_engine.cc new file mode 100644 index 0000000000000000000000000000000000000000..7416441d7902e5cb1455e6dd09fc7537a6b0df3a --- /dev/null +++ b/shell/platform/embedder/embedder_engine.cc @@ -0,0 +1,119 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..c01b86c2aac47531f8db7c6e2d3f59855e8ca8e5 --- /dev/null +++ b/shell/platform/embedder/embedder_engine.h @@ -0,0 +1,53 @@ +// 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 46e0390770da42d53a2aeb73bc23d2d697116b5f..db1bea35c691e9197a70180c0bd9f3cb134f8a0a 100644 --- a/shell/platform/embedder/platform_view_embedder.cc +++ b/shell/platform/embedder/platform_view_embedder.cc @@ -3,17 +3,18 @@ // found in the LICENSE file. #include "flutter/shell/platform/embedder/platform_view_embedder.h" -#include "flutter/shell/gpu/gpu_rasterizer.h" + +#include "flutter/shell/common/io_manager.h" namespace shell { -PlatformViewEmbedder::PlatformViewEmbedder(DispatchTable dispatch_table) - : PlatformView(std::make_unique(nullptr)), +PlatformViewEmbedder::PlatformViewEmbedder(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + DispatchTable dispatch_table) + : PlatformView(delegate, std::move(task_runners)), dispatch_table_(dispatch_table) {} -PlatformViewEmbedder::~PlatformViewEmbedder() { - NotifyDestroyed(); -} +PlatformViewEmbedder::~PlatformViewEmbedder() = default; bool PlatformViewEmbedder::GLContextMakeCurrent() { return dispatch_table_.gl_make_current_callback(); @@ -31,33 +32,6 @@ 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) { @@ -76,4 +50,17 @@ 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 c287fc5ac86f1d9e98026d8ca35ee3c9eded41ce..a5b76dfaa07bac93460d4bfe90215f35a93dab26 100644 --- a/shell/platform/embedder/platform_view_embedder.h +++ b/shell/platform/embedder/platform_view_embedder.h @@ -12,7 +12,8 @@ namespace shell { -class PlatformViewEmbedder : public PlatformView, public GPUSurfaceGLDelegate { +class PlatformViewEmbedder final : public PlatformView, + public GPUSurfaceGLDelegate { public: using PlatformMessageResponseCallback = std::function)>; @@ -26,9 +27,11 @@ class PlatformViewEmbedder : public PlatformView, public GPUSurfaceGLDelegate { std::function gl_make_resource_current_callback; // optional }; - PlatformViewEmbedder(DispatchTable dispatch_table); + PlatformViewEmbedder(PlatformView::Delegate& delegate, + blink::TaskRunners task_runners, + DispatchTable dispatch_table); - ~PlatformViewEmbedder(); + ~PlatformViewEmbedder() override; // |shell::GPUSurfaceGLDelegate| bool GLContextMakeCurrent() override; @@ -42,20 +45,6 @@ class PlatformViewEmbedder : public PlatformView, public GPUSurfaceGLDelegate { // |shell::GPUSurfaceGLDelegate| intptr_t GLContextFBO() const override; - // |shell::PlatformView| - void Attach() override; - - // |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| - void SetAssetBundlePath(const std::string& assets_directory) override; - // |shell::PlatformView| void HandlePlatformMessage( fxl::RefPtr message) override; @@ -63,6 +52,12 @@ class PlatformViewEmbedder : public PlatformView, public GPUSurfaceGLDelegate { private: DispatchTable dispatch_table_; + // |shell::PlatformView| + std::unique_ptr CreateRenderingSurface() override; + + // |shell::PlatformView| + sk_sp CreateResourceContext() const override; + FXL_DISALLOW_COPY_AND_ASSIGN(PlatformViewEmbedder); }; diff --git a/shell/platform/linux/BUILD.gn b/shell/platform/linux/BUILD.gn deleted file mode 100644 index 6e9f1f596b09db8017a672912ae64c73030d923a..0000000000000000000000000000000000000000 --- a/shell/platform/linux/BUILD.gn +++ /dev/null @@ -1,23 +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. - -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 deleted file mode 100644 index a20d425ed1eedd9adc57c910550599cbcbee4e58..0000000000000000000000000000000000000000 --- a/shell/platform/linux/main_linux.cc +++ /dev/null @@ -1,142 +0,0 @@ -// 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 deleted file mode 100644 index b4a2fe5033c1899fee9b8d76fa181ec3e19fe6e3..0000000000000000000000000000000000000000 --- a/shell/platform/win/BUILD.gn +++ /dev/null @@ -1,30 +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. - -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 deleted file mode 100644 index c31c88ca915cbe7dd67ff632cffd68400cbfe6b4..0000000000000000000000000000000000000000 --- a/shell/platform/win/main_win.cc +++ /dev/null @@ -1,142 +0,0 @@ -// 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 659c241cc49b80012c6f7b70ff7f1a7d7ea5280d..f11a3a2d07501d8c789a04ea6340dcc8dae3f11f 100644 --- a/shell/testing/BUILD.gn +++ b/shell/testing/BUILD.gn @@ -2,24 +2,30 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -source_set("testing") { +executable("testing") { + testonly = true + + output_name = "flutter_tester" + + public_configs = [ "$flutter_root:config" ] + sources = [ - "platform_view_test.cc", - "platform_view_test.h", - "test_runner.cc", - "test_runner.h", - "testing.cc", - "testing.h", + "tester_main.cc", ] 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", ] - public_configs = [ - "$flutter_root:config", - ] + if (is_linux) { + ldflags = [ "-rdynamic" ] + } } diff --git a/shell/testing/platform_view_test.cc b/shell/testing/platform_view_test.cc deleted file mode 100644 index a59684d31bc9448ce9548df621a923314ef693d5..0000000000000000000000000000000000000000 --- a/shell/testing/platform_view_test.cc +++ /dev/null @@ -1,32 +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. - -#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 deleted file mode 100644 index 3612d0363ab58a26a4317bbc8275228cb613dd1f..0000000000000000000000000000000000000000 --- a/shell/testing/platform_view_test.h +++ /dev/null @@ -1,38 +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. - -#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 deleted file mode 100644 index 838b04120c77391da875d5edee3622b0de743b03..0000000000000000000000000000000000000000 --- a/shell/testing/test_runner.cc +++ /dev/null @@ -1,48 +0,0 @@ -// 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 deleted file mode 100644 index 8f303d7eb7683a90ccf031e7f074959ca32d952d..0000000000000000000000000000000000000000 --- a/shell/testing/test_runner.h +++ /dev/null @@ -1,42 +0,0 @@ -// 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 new file mode 100644 index 0000000000000000000000000000000000000000..a9e7bafc74d93f153e55eeec6e08c6dbe5ff55d8 --- /dev/null +++ b/shell/testing/tester_main.cc @@ -0,0 +1,243 @@ +// 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 deleted file mode 100644 index 13a3ab5be3d9330c3229436ab0c9f8786f35bb50..0000000000000000000000000000000000000000 --- a/shell/testing/testing.cc +++ /dev/null @@ -1,24 +0,0 @@ -// 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 deleted file mode 100644 index 99f8b4fe983de77065381a17754bd0b85e2414b1..0000000000000000000000000000000000000000 --- a/shell/testing/testing.h +++ /dev/null @@ -1,16 +0,0 @@ -// 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 8577ab16f29389fee7c8329525ae01cac9647401..bc94f22e97ce672c9b84f738724de9f2c8d25f42 100644 --- a/sky/engine/platform/SharedBuffer.cpp +++ b/sky/engine/platform/SharedBuffer.cpp @@ -26,7 +26,6 @@ #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 177f161adaa7e599f424730bb6b59d146d8fd18a..4786d65e0d7ada38fc4cd4aa6a9d2a3af41e1986 100644 --- a/sky/engine/platform/fonts/FontFallbackList.cpp +++ b/sky/engine/platform/fonts/FontFallbackList.cpp @@ -37,6 +37,11 @@ namespace blink { +bool gUseTestFonts = false; +void FontFallbackList::SetUseTestFonts(bool useTestFonts) { + gUseTestFonts = useTestFonts; +} + FontFallbackList::FontFallbackList() : m_pageZero(0), m_cachedPrimarySimpleFontData(0), @@ -45,7 +50,8 @@ FontFallbackList::FontFallbackList() m_familyIndex(0), m_generation(FontCache::fontCache()->generation()), m_pitch(UnknownPitch), - m_hasLoadingFallback(false) {} + m_hasLoadingFallback(false), + m_useTestFonts(gUseTestFonts) {} void FontFallbackList::invalidate(PassRefPtr fontSelector) { releaseFontData(); @@ -193,7 +199,7 @@ PassRefPtr FontFallbackList::getFontData( const FontFamily* currFamily = startFamily; while (currFamily && !result) { familyIndex++; - if (currFamily->family().length() || Settings::Get().use_test_fonts) { + if (currFamily->family().length() || m_useTestFonts) { 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 fdac27e5013bd58ed1f5016b64c350ade1636d92..3331387968edc00a7cc2546ca1a1a3b056fbf8c6 100644 --- a/sky/engine/platform/fonts/FontFallbackList.h +++ b/sky/engine/platform/fonts/FontFallbackList.h @@ -103,6 +103,8 @@ class PLATFORM_EXPORT FontFallbackList : public RefCounted { m_pageZero = node; } + static void SetUseTestFonts(bool useTestFonts); + private: FontFallbackList(); @@ -125,6 +127,7 @@ 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 e90539e96cf8796af88e3db7c030fc2cde2d06c9..52c6243743d7b3b6d4172f1198612258857c8441 100644 --- a/sky/engine/web/Sky.cpp +++ b/sky/engine/web/Sky.cpp @@ -53,56 +53,6 @@ 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; @@ -130,15 +80,9 @@ 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 977a571c8da309d652470231a5bf3567b61c87bd..9ee7680cc116073c1ba44b30033f403738472cf3 100644 --- a/synchronization/BUILD.gn +++ b/synchronization/BUILD.gn @@ -4,16 +4,13 @@ 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 deleted file mode 100644 index 69614eb89d217fb597ea87e6e6d007859f725e33..0000000000000000000000000000000000000000 --- a/synchronization/debug_thread_checker.h +++ /dev/null @@ -1,25 +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. - -#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 c6e0bdf9e2d5393e2cb9ccfbb5336206ab850b91..4dc5f6220e35097c1261c6626ed72acbfc0cd4ca 100644 --- a/synchronization/semaphore.cc +++ b/synchronization/semaphore.cc @@ -15,9 +15,12 @@ namespace flutter { class PlatformSemaphore { public: explicit PlatformSemaphore(uint32_t count) - : _sem(dispatch_semaphore_create(count)) {} + : _sem(dispatch_semaphore_create(count)), _initial(count) {} ~PlatformSemaphore() { + for (uint32_t i = 0; i < _initial; ++i) { + Signal(); + } if (_sem != nullptr) { dispatch_release(reinterpret_cast(_sem)); _sem = nullptr; @@ -42,6 +45,7 @@ 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 3927e71cfc0e4964defa27c936968ebb41f0d1a7..a65311bfaeb7cbdc5be448c7487d060960928d45 100644 --- a/testing/BUILD.gn +++ b/testing/BUILD.gn @@ -9,9 +9,13 @@ 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 new file mode 100644 index 0000000000000000000000000000000000000000..1306f37678fbefc2a95defdbe649a8a6c1a73b83 --- /dev/null +++ b/testing/thread_test.cc @@ -0,0 +1,33 @@ +// 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 new file mode 100644 index 0000000000000000000000000000000000000000..511d09c978858b00b81a3164b5b2340da7ea62cb --- /dev/null +++ b/testing/thread_test.h @@ -0,0 +1,37 @@ +// 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 ea7071ac0a474972e5423254fc46258fdae0fdcd..b4b15f99f1d4fc6f2cc1bd3872836de10d5b819c 100755 --- a/tools/gn +++ b/tools/gn @@ -232,6 +232,10 @@ 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 8749f6880dbf49009857043c5b84b72858e8421a..b15c6084250951153b1ff294b942501a1d8093f1 100644 --- a/travis/licenses_golden/licenses_flutter +++ b/travis/licenses_golden/licenses_flutter @@ -1059,14 +1059,10 @@ USED LICENSES: ==================================================================================================== LIBRARY: engine LIBRARY: txt -ORIGIN: ../../../flutter/content_handler/service_protocol_hooks.cc + ../../../LICENSE +ORIGIN: ../../../flutter/content_handler/session_connection.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 @@ -1126,7 +1122,6 @@ 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 @@ -1142,13 +1137,10 @@ 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 @@ -1195,8 +1187,6 @@ 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 @@ -1563,7 +1553,6 @@ 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 @@ -1638,17 +1627,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: engine -ORIGIN: ../../../flutter/assets/asset_provider.h + ../../../LICENSE +ORIGIN: ../../../flutter/assets/asset_manager.cc + ../../../LICENSE TYPE: LicenseType.bsd -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 +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 ---------------------------------------------------------------------------------------------------- -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 @@ -1683,23 +1703,10 @@ 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 @@ -1707,7 +1714,6 @@ 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 @@ -1718,9 +1724,6 @@ 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 @@ -1742,18 +1745,13 @@ 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/runtime_init.cc -FILE: ../../../flutter/runtime/runtime_init.h +FILE: ../../../flutter/runtime/fixtures/simple_main.dart 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 @@ -1782,8 +1780,6 @@ 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 @@ -1792,8 +1788,6 @@ 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 @@ -1816,7 +1810,6 @@ 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 @@ -1884,15 +1877,68 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ==================================================================================================== LIBRARY: engine -ORIGIN: ../../../flutter/flow/layers/default_layer_builder.cc + ../../../LICENSE +ORIGIN: ../../../flutter/content_handler/application.cc + ../../../garnet/LICENSE TYPE: LicenseType.bsd -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 +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 2017 The Flutter Authors. All rights reserved. +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 +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 +---------------------------------------------------------------------------------------------------- +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 @@ -1957,6 +2003,62 @@ 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 @@ -9873,10 +9975,6 @@ 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 @@ -9896,13 +9994,9 @@ 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 @@ -9915,12 +10009,6 @@ 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 @@ -9930,8 +10018,6 @@ 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 ---------------------------------------------------------------------------------------------------- @@ -9968,6 +10054,7 @@ 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 @@ -10001,4 +10088,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: 216 +Total license count: 218