Skip to content

Commit 15c5874

Browse files
author
Jonah Williams
authored
Preserve specified AssetResolvers when performing a hot restart or updating the asset directory (flutter#21611)
Follow up from flutter#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.
1 parent 4c6f2ad commit 15c5874

File tree

13 files changed

+103
-31
lines changed

13 files changed

+103
-31
lines changed

assets/asset_manager.cc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ void AssetManager::PushBack(std::unique_ptr<AssetResolver> resolver) {
2929
resolvers_.push_back(std::move(resolver));
3030
}
3131

32+
std::deque<std::unique_ptr<AssetResolver>> AssetManager::TakeResolvers() {
33+
return std::move(resolvers_);
34+
}
35+
3236
// |AssetResolver|
3337
std::unique_ptr<fml::Mapping> AssetManager::GetAsMapping(
3438
const std::string& asset_name) const {
@@ -52,4 +56,9 @@ bool AssetManager::IsValid() const {
5256
return resolvers_.size() > 0;
5357
}
5458

59+
// |AssetResolver|
60+
bool AssetManager::IsValidAfterAssetManagerChange() const {
61+
return false;
62+
}
63+
5564
} // namespace flutter

assets/asset_manager.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,14 @@ class AssetManager final : public AssetResolver {
2525

2626
void PushBack(std::unique_ptr<AssetResolver> resolver);
2727

28+
std::deque<std::unique_ptr<AssetResolver>> TakeResolvers();
29+
2830
// |AssetResolver|
2931
bool IsValid() const override;
3032

33+
// |AssetResolver|
34+
bool IsValidAfterAssetManagerChange() const override;
35+
3136
// |AssetResolver|
3237
std::unique_ptr<fml::Mapping> GetAsMapping(
3338
const std::string& asset_name) const override;

assets/asset_resolver.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ class AssetResolver {
2121

2222
virtual bool IsValid() const = 0;
2323

24+
//----------------------------------------------------------------------------
25+
/// @brief Certain asset resolvers are still valid after the asset
26+
/// manager is replaced before a hot reload, or after a new run
27+
/// configuration is created during a hot restart. By preserving
28+
/// these resolvers and re-inserting them into the new resolver or
29+
/// run configuration, the tooling can avoid needing to sync all
30+
/// application assets through the Dart devFS upon connecting to
31+
/// the VM Service. Besides improving the startup performance of
32+
/// running a Flutter application, it also reduces the occurance
33+
/// of tool failures due to repeated network flakes caused by
34+
/// damaged cables or hereto unknown bugs in the Dart HTTP server
35+
/// implementation.
36+
///
37+
/// @return Returns whether this resolver is valid after the asset manager
38+
/// or run configuration is updated.
39+
///
40+
virtual bool IsValidAfterAssetManagerChange() const = 0;
41+
2442
[[nodiscard]] virtual std::unique_ptr<fml::Mapping> GetAsMapping(
2543
const std::string& asset_name) const = 0;
2644

assets/directory_asset_bundle.cc

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@
1212

1313
namespace flutter {
1414

15-
DirectoryAssetBundle::DirectoryAssetBundle(fml::UniqueFD descriptor)
15+
DirectoryAssetBundle::DirectoryAssetBundle(
16+
fml::UniqueFD descriptor,
17+
bool is_valid_after_asset_manager_change)
1618
: descriptor_(std::move(descriptor)) {
1719
if (!fml::IsDirectory(descriptor_)) {
1820
return;
1921
}
22+
is_valid_after_asset_manager_change_ = is_valid_after_asset_manager_change;
2023
is_valid_ = true;
2124
}
2225

@@ -27,6 +30,11 @@ bool DirectoryAssetBundle::IsValid() const {
2730
return is_valid_;
2831
}
2932

33+
// |AssetResolver|
34+
bool DirectoryAssetBundle::IsValidAfterAssetManagerChange() const {
35+
return is_valid_after_asset_manager_change_;
36+
}
37+
3038
// |AssetResolver|
3139
std::unique_ptr<fml::Mapping> DirectoryAssetBundle::GetAsMapping(
3240
const std::string& asset_name) const {

assets/directory_asset_bundle.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,22 @@ namespace flutter {
1414

1515
class DirectoryAssetBundle : public AssetResolver {
1616
public:
17-
explicit DirectoryAssetBundle(fml::UniqueFD descriptor);
17+
DirectoryAssetBundle(fml::UniqueFD descriptor,
18+
bool is_valid_after_asset_manager_change);
1819

1920
~DirectoryAssetBundle() override;
2021

2122
private:
2223
const fml::UniqueFD descriptor_;
2324
bool is_valid_ = false;
25+
bool is_valid_after_asset_manager_change_ = false;
2426

2527
// |AssetResolver|
2628
bool IsValid() const override;
2729

30+
// |AssetResolver|
31+
bool IsValidAfterAssetManagerChange() const override;
32+
2833
// |AssetResolver|
2934
std::unique_ptr<fml::Mapping> GetAsMapping(
3035
const std::string& asset_name) const override;

shell/common/engine.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ void Engine::SetupDefaultFontManager() {
106106
font_collection_.SetupDefaultFontManager();
107107
}
108108

109+
std::shared_ptr<AssetManager> Engine::GetAssetManager() {
110+
return asset_manager_;
111+
}
112+
109113
bool Engine::UpdateAssetManager(
110114
std::shared_ptr<AssetManager> new_asset_manager) {
111115
if (asset_manager_ == new_asset_manager) {

shell/common/engine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,9 @@ class Engine final : public RuntimeDelegate,
734734
// |RuntimeDelegate|
735735
FontCollection& GetFontCollection() override;
736736

737+
// Return the asset manager associated with the current engine, or nullptr.
738+
std::shared_ptr<AssetManager> GetAssetManager();
739+
737740
// |PointerDataDispatcher::Delegate|
738741
void DoDispatchPacket(std::unique_ptr<PointerDataPacket> packet,
739742
uint64_t trace_flow_id) override;

shell/common/persistent_cache_unittests.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,10 @@ TEST_F(ShellTest, CanLoadSkSLsFromAsset) {
185185
ResetAssetManager();
186186
auto asset_manager = std::make_shared<AssetManager>();
187187
RunConfiguration config(nullptr, asset_manager);
188-
asset_manager->PushBack(
189-
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
190-
asset_dir.path().c_str(), false, fml::FilePermission::kRead)));
188+
asset_manager->PushBack(std::make_unique<DirectoryAssetBundle>(
189+
fml::OpenDirectory(asset_dir.path().c_str(), false,
190+
fml::FilePermission::kRead),
191+
false));
191192
CheckTwoSkSLsAreLoaded();
192193

193194
// 3rd, test the content of the SkSLs in the asset.

shell/common/run_configuration.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,13 @@ RunConfiguration RunConfiguration::InferFromSettings(
2121

2222
if (fml::UniqueFD::traits_type::IsValid(settings.assets_dir)) {
2323
asset_manager->PushBack(std::make_unique<DirectoryAssetBundle>(
24-
fml::Duplicate(settings.assets_dir)));
24+
fml::Duplicate(settings.assets_dir), true));
2525
}
2626

27-
asset_manager->PushBack(
28-
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
29-
settings.assets_path.c_str(), false, fml::FilePermission::kRead)));
27+
asset_manager->PushBack(std::make_unique<DirectoryAssetBundle>(
28+
fml::OpenDirectory(settings.assets_path.c_str(), false,
29+
fml::FilePermission::kRead),
30+
true));
3031

3132
return {IsolateConfiguration::InferFromSettings(settings, asset_manager,
3233
io_worker),

shell/common/shell.cc

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,10 +1401,21 @@ bool Shell::OnServiceProtocolRunInView(
14011401
configuration.SetEntrypointAndLibrary(engine_->GetLastEntrypoint(),
14021402
engine_->GetLastEntrypointLibrary());
14031403

1404-
configuration.AddAssetResolver(
1405-
std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
1406-
asset_directory_path.c_str(), false, fml::FilePermission::kRead)));
1407-
configuration.AddAssetResolver(RestoreOriginalAssetResolver());
1404+
configuration.AddAssetResolver(std::make_unique<DirectoryAssetBundle>(
1405+
fml::OpenDirectory(asset_directory_path.c_str(), false,
1406+
fml::FilePermission::kRead),
1407+
false));
1408+
1409+
// Preserve any original asset resolvers to avoid syncing unchanged assets
1410+
// over the DevFS connection.
1411+
auto old_asset_manager = engine_->GetAssetManager();
1412+
if (old_asset_manager != nullptr) {
1413+
for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
1414+
if (old_resolver->IsValidAfterAssetManagerChange()) {
1415+
configuration.AddAssetResolver(std::move(old_resolver));
1416+
}
1417+
}
1418+
}
14081419

14091420
auto& allocator = response->GetAllocator();
14101421
response->SetObject();
@@ -1517,10 +1528,21 @@ bool Shell::OnServiceProtocolSetAssetBundlePath(
15171528

15181529
auto asset_manager = std::make_shared<AssetManager>();
15191530

1520-
asset_manager->PushFront(RestoreOriginalAssetResolver());
15211531
asset_manager->PushFront(std::make_unique<DirectoryAssetBundle>(
15221532
fml::OpenDirectory(params.at("assetDirectory").data(), false,
1523-
fml::FilePermission::kRead)));
1533+
fml::FilePermission::kRead),
1534+
false));
1535+
1536+
// Preserve any original asset resolvers to avoid syncing unchanged assets
1537+
// over the DevFS connection.
1538+
auto old_asset_manager = engine_->GetAssetManager();
1539+
if (old_asset_manager != nullptr) {
1540+
for (auto& old_resolver : old_asset_manager->TakeResolvers()) {
1541+
if (old_resolver->IsValidAfterAssetManagerChange()) {
1542+
asset_manager->PushBack(std::move(old_resolver));
1543+
}
1544+
}
1545+
}
15241546

15251547
if (engine_->UpdateAssetManager(std::move(asset_manager))) {
15261548
response->AddMember("type", "Success", allocator);
@@ -1624,16 +1646,4 @@ void Shell::OnDisplayUpdates(DisplayUpdateType update_type,
16241646
display_manager_->HandleDisplayUpdates(update_type, displays);
16251647
}
16261648

1627-
// Add the original asset directory to the resolvers so that unmodified assets
1628-
// bundled with the application specific format (APK, IPA) can be used without
1629-
// syncing to the Dart devFS.
1630-
std::unique_ptr<DirectoryAssetBundle> Shell::RestoreOriginalAssetResolver() {
1631-
if (fml::UniqueFD::traits_type::IsValid(settings_.assets_dir)) {
1632-
return std::make_unique<DirectoryAssetBundle>(
1633-
fml::Duplicate(settings_.assets_dir));
1634-
}
1635-
return std::make_unique<DirectoryAssetBundle>(fml::OpenDirectory(
1636-
settings_.assets_path.c_str(), false, fml::FilePermission::kRead));
1637-
};
1638-
16391649
} // namespace flutter

0 commit comments

Comments
 (0)