未验证 提交 15c58740 编写于 作者: J Jonah Williams 提交者: GitHub

Preserve specified AssetResolvers when performing a hot restart or updating...

Preserve specified AssetResolvers when performing a hot restart or updating the asset directory (#21611)

Follow up from #21436 . That PR works for all embeddings except for Android, which creates a special JNI AssetResolver. Since the shell cannot recreate this resolver, update the logic to preserve existing resolvers instead.
上级 4c6f2ad7
......@@ -29,6 +29,10 @@ void AssetManager::PushBack(std::unique_ptr<AssetResolver> resolver) {
resolvers_.push_back(std::move(resolver));
}
std::deque<std::unique_ptr<AssetResolver>> AssetManager::TakeResolvers() {
return std::move(resolvers_);
}
// |AssetResolver|
std::unique_ptr<fml::Mapping> AssetManager::GetAsMapping(
const std::string& asset_name) const {
......@@ -52,4 +56,9 @@ bool AssetManager::IsValid() const {
return resolvers_.size() > 0;
}
// |AssetResolver|
bool AssetManager::IsValidAfterAssetManagerChange() const {
return false;
}
} // namespace flutter
......@@ -25,9 +25,14 @@ class AssetManager final : public AssetResolver {
void PushBack(std::unique_ptr<AssetResolver> resolver);
std::deque<std::unique_ptr<AssetResolver>> TakeResolvers();
// |AssetResolver|
bool IsValid() const override;
// |AssetResolver|
bool IsValidAfterAssetManagerChange() const override;
// |AssetResolver|
std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const override;
......
......@@ -21,6 +21,24 @@ class AssetResolver {
virtual bool IsValid() const = 0;
//----------------------------------------------------------------------------
/// @brief Certain asset resolvers are still valid after the asset
/// manager is replaced before a hot reload, or after a new run
/// configuration is created during a hot restart. By preserving
/// these resolvers and re-inserting them into the new resolver or
/// run configuration, the tooling can avoid needing to sync all
/// application assets through the Dart devFS upon connecting to
/// the VM Service. Besides improving the startup performance of
/// running a Flutter application, it also reduces the occurance
/// of tool failures due to repeated network flakes caused by
/// damaged cables or hereto unknown bugs in the Dart HTTP server
/// implementation.
///
/// @return Returns whether this resolver is valid after the asset manager
/// or run configuration is updated.
///
virtual bool IsValidAfterAssetManagerChange() const = 0;
[[nodiscard]] virtual std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const = 0;
......
......@@ -12,11 +12,14 @@
namespace flutter {
DirectoryAssetBundle::DirectoryAssetBundle(fml::UniqueFD descriptor)
DirectoryAssetBundle::DirectoryAssetBundle(
fml::UniqueFD descriptor,
bool is_valid_after_asset_manager_change)
: descriptor_(std::move(descriptor)) {
if (!fml::IsDirectory(descriptor_)) {
return;
}
is_valid_after_asset_manager_change_ = is_valid_after_asset_manager_change;
is_valid_ = true;
}
......@@ -27,6 +30,11 @@ bool DirectoryAssetBundle::IsValid() const {
return is_valid_;
}
// |AssetResolver|
bool DirectoryAssetBundle::IsValidAfterAssetManagerChange() const {
return is_valid_after_asset_manager_change_;
}
// |AssetResolver|
std::unique_ptr<fml::Mapping> DirectoryAssetBundle::GetAsMapping(
const std::string& asset_name) const {
......
......@@ -14,17 +14,22 @@ namespace flutter {
class DirectoryAssetBundle : public AssetResolver {
public:
explicit DirectoryAssetBundle(fml::UniqueFD descriptor);
DirectoryAssetBundle(fml::UniqueFD descriptor,
bool is_valid_after_asset_manager_change);
~DirectoryAssetBundle() override;
private:
const fml::UniqueFD descriptor_;
bool is_valid_ = false;
bool is_valid_after_asset_manager_change_ = false;
// |AssetResolver|
bool IsValid() const override;
// |AssetResolver|
bool IsValidAfterAssetManagerChange() const override;
// |AssetResolver|
std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const override;
......
......@@ -106,6 +106,10 @@ void Engine::SetupDefaultFontManager() {
font_collection_.SetupDefaultFontManager();
}
std::shared_ptr<AssetManager> Engine::GetAssetManager() {
return asset_manager_;
}
bool Engine::UpdateAssetManager(
std::shared_ptr<AssetManager> new_asset_manager) {
if (asset_manager_ == new_asset_manager) {
......
......@@ -734,6 +734,9 @@ class Engine final : public RuntimeDelegate,
// |RuntimeDelegate|
FontCollection& GetFontCollection() override;
// Return the asset manager associated with the current engine, or nullptr.
std::shared_ptr<AssetManager> GetAssetManager();
// |PointerDataDispatcher::Delegate|
void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
uint64_t trace_flow_id) override;
......
......@@ -185,9 +185,10 @@ TEST_F(ShellTest, CanLoadSkSLsFromAsset) {
ResetAssetManager();
auto asset_manager = std::make_shared<AssetManager>();
RunConfiguration config(nullptr, asset_manager);
asset_manager->PushBack(
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
asset_dir.path().c_str(), false, fml::FilePermission::kRead)));
asset_manager->PushBack(std::make_unique<DirectoryAssetBundle>(
fml::OpenDirectory(asset_dir.path().c_str(), false,
fml::FilePermission::kRead),
false));
CheckTwoSkSLsAreLoaded();
// 3rd, test the content of the SkSLs in the asset.
......
......@@ -21,12 +21,13 @@ RunConfiguration RunConfiguration::InferFromSettings(
if (fml::UniqueFD::traits_type::IsValid(settings.assets_dir)) {
asset_manager->PushBack(std::make_unique<DirectoryAssetBundle>(
fml::Duplicate(settings.assets_dir)));
fml::Duplicate(settings.assets_dir), true));
}
asset_manager->PushBack(
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
settings.assets_path.c_str(), false, fml::FilePermission::kRead)));
asset_manager->PushBack(std::make_unique<DirectoryAssetBundle>(
fml::OpenDirectory(settings.assets_path.c_str(), false,
fml::FilePermission::kRead),
true));
return {IsolateConfiguration::InferFromSettings(settings, asset_manager,
io_worker),
......
......@@ -1401,10 +1401,21 @@ bool Shell::OnServiceProtocolRunInView(
configuration.SetEntrypointAndLibrary(engine_->GetLastEntrypoint(),
engine_->GetLastEntrypointLibrary());
configuration.AddAssetResolver(
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
asset_directory_path.c_str(), false, fml::FilePermission::kRead)));
configuration.AddAssetResolver(RestoreOriginalAssetResolver());
configuration.AddAssetResolver(std::make_unique<DirectoryAssetBundle>(
fml::OpenDirectory(asset_directory_path.c_str(), false,
fml::FilePermission::kRead),
false));
// Preserve any original asset resolvers to avoid syncing unchanged assets
// over the DevFS connection.
auto old_asset_manager = engine_->GetAssetManager();
if (old_asset_manager != nullptr) {
for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
if (old_resolver->IsValidAfterAssetManagerChange()) {
configuration.AddAssetResolver(std::move(old_resolver));
}
}
}
auto& allocator = response->GetAllocator();
response->SetObject();
......@@ -1517,10 +1528,21 @@ bool Shell::OnServiceProtocolSetAssetBundlePath(
auto asset_manager = std::make_shared<AssetManager>();
asset_manager->PushFront(RestoreOriginalAssetResolver());
asset_manager->PushFront(std::make_unique<DirectoryAssetBundle>(
fml::OpenDirectory(params.at("assetDirectory").data(), false,
fml::FilePermission::kRead)));
fml::FilePermission::kRead),
false));
// Preserve any original asset resolvers to avoid syncing unchanged assets
// over the DevFS connection.
auto old_asset_manager = engine_->GetAssetManager();
if (old_asset_manager != nullptr) {
for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
if (old_resolver->IsValidAfterAssetManagerChange()) {
asset_manager->PushBack(std::move(old_resolver));
}
}
}
if (engine_->UpdateAssetManager(std::move(asset_manager))) {
response->AddMember("type", "Success", allocator);
......@@ -1624,16 +1646,4 @@ void Shell::OnDisplayUpdates(DisplayUpdateType update_type,
display_manager_->HandleDisplayUpdates(update_type, displays);
}
// Add the original asset directory to the resolvers so that unmodified assets
// bundled with the application specific format (APK, IPA) can be used without
// syncing to the Dart devFS.
std::unique_ptr<DirectoryAssetBundle> Shell::RestoreOriginalAssetResolver() {
if (fml::UniqueFD::traits_type::IsValid(settings_.assets_dir)) {
return std::make_unique<DirectoryAssetBundle>(
fml::Duplicate(settings_.assets_dir));
}
return std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
settings_.assets_path.c_str(), false, fml::FilePermission::kRead));
};
} // namespace flutter
......@@ -27,6 +27,10 @@ bool APKAssetProvider::IsValid() const {
return true;
}
bool APKAssetProvider::IsValidAfterAssetManagerChange() const {
return true;
}
class APKAssetMapping : public fml::Mapping {
public:
APKAssetMapping(AAsset* asset) : asset_(asset) {}
......
......@@ -29,6 +29,9 @@ class APKAssetProvider final : public AssetResolver {
// |flutter::AssetResolver|
bool IsValid() const override;
// |flutter::AssetResolver|
bool IsValidAfterAssetManagerChange() const override;
// |flutter::AssetResolver|
std::unique_ptr<fml::Mapping> GetAsMapping(
const std::string& asset_name) const override;
......
......@@ -192,10 +192,11 @@ int RunTester(const flutter::Settings& settings,
auto asset_manager = std::make_shared<flutter::AssetManager>();
asset_manager->PushBack(std::make_unique<flutter::DirectoryAssetBundle>(
fml::Duplicate(settings.assets_dir)));
asset_manager->PushBack(
std::make_unique<flutter::DirectoryAssetBundle>(fml::OpenDirectory(
settings.assets_path.c_str(), false, fml::FilePermission::kRead)));
fml::Duplicate(settings.assets_dir), true));
asset_manager->PushBack(std::make_unique<flutter::DirectoryAssetBundle>(
fml::OpenDirectory(settings.assets_path.c_str(), false,
fml::FilePermission::kRead),
true));
RunConfiguration run_configuration(std::move(isolate_configuration),
std::move(asset_manager));
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册