Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 764b91d

Browse files
authored
[native assets] Consume NativeAssetsManifest.json (#56727)
This PR introduces a `NativeAssetsManifest.json` next to the `AssetManifest.json` and `FontManifest.json`. This removes the need for embedding the native assets mapping inside the kernel file and will enable decoupling native assets building and bundling from the kernel compilation in flutter tools. This will then allow us to remove dry-run from the build hook protocol. (It also means all isolate groups will have the same native assets. However, since Flutter does not support `Isolate.spawnUri` from kernel files anyways, this is not a regression.) This manifest is parsed eagerly on startup by the engine in a manner similar to how the font manifest is parsed. The manifest contents need to be available in the callback for resolving assets, which does not have access to the engine. Therefore the parsed manifest is `NativeAssetsManager` stored in the `IsolateGroupData`. The engine passes it in on isolate group creation, and the FFI callbacks access it from the isolate group data. Issue: * flutter/flutter#154425 Related PRs: * https://dart-review.googlesource.com/c/sdk/+/388161 Follow up work: * This PR does not yet remove the engine callbacks registered via the dart_api that rely on kernel embedding. If we were to do that in this PR, it would require a manual roll of the engine into flutter/flutter with the PR that switches flutter_tools to emit the native assets manifest instead of embedding in kernel, and a manual roll into g3 to switch emitting a manifest instead of embedding in kernel. A TODO is left in the code for those callbacks to be removed. ## Testing Most of this PR cannot be tested in isolation. The code in this PR is heavily exercised in the follow up flutter_tools PR which creates the `NativeAssetsManifest.json` and removes the embedding of native assets in kernel files. * This PR adds a unit test for parsing the JSON manifest. [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent ec065be commit 764b91d

21 files changed

+439
-50
lines changed

BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ group("unittests") {
183183
# Compile all unittests targets if enabled.
184184
if (enable_unittests) {
185185
public_deps += [
186+
"//flutter/assets:assets_unittests",
186187
"//flutter/display_list:display_list_rendertests",
187188
"//flutter/display_list:display_list_unittests",
188189
"//flutter/flow:flow_unittests",

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ $ ./run_tests.py --variant=host_debug_unopt_arm64 --type=engine
243243
| Name | run_tests.py type | Description |
244244
| ---------------------------------------- | ------------------- | --------------------------------------------------------------- |
245245
| accessibility_unittests | engine | |
246+
| assets_unittests | engine | |
246247
| client_wrapper_glfw_unittests | engine | |
247248
| client_wrapper_unittests | engine | |
248249
| common_cpp_core_unittests | engine | |

assets/BUILD.gn

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,57 @@
22
# Use of this source code is governed by a BSD-style license that can be
33
# found in the LICENSE file.
44

5+
import("//flutter/common/config.gni")
6+
import("//flutter/testing/testing.gni")
7+
8+
if (is_fuchsia) {
9+
import("//flutter/tools/fuchsia/gn-sdk/src/gn_configs.gni")
10+
}
11+
512
source_set("assets") {
613
sources = [
714
"asset_manager.cc",
815
"asset_manager.h",
916
"asset_resolver.h",
1017
"directory_asset_bundle.cc",
1118
"directory_asset_bundle.h",
19+
"native_assets.cc",
20+
"native_assets.h",
1221
]
1322

1423
deps = [
1524
"//flutter/common",
1625
"//flutter/fml",
26+
"//flutter/third_party/rapidjson",
1727
]
1828

1929
public_configs = [ "//flutter:config" ]
2030
}
31+
32+
test_fixtures("assets_fixtures") {
33+
fixtures = []
34+
}
35+
36+
if (enable_unittests) {
37+
executable("assets_unittests") {
38+
testonly = true
39+
40+
sources = [ "native_assets_unittests.cc" ]
41+
42+
deps = [
43+
":assets",
44+
":assets_fixtures",
45+
"//flutter/testing",
46+
]
47+
48+
if (!defined(defines)) {
49+
defines = []
50+
}
51+
52+
# This is needed for //flutter/third_party/googletest for linking zircon
53+
# symbols.
54+
if (is_fuchsia) {
55+
libs = [ "${fuchsia_arch_root}/sysroot/lib/libzircon.so" ]
56+
}
57+
}
58+
}

assets/native_assets.cc

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "assets/native_assets.h"
6+
7+
#include "flutter/fml/build_config.h"
8+
#include "rapidjson/document.h"
9+
10+
namespace flutter {
11+
12+
#if defined(FML_ARCH_CPU_ARMEL)
13+
#define kTargetArchitectureName "arm"
14+
#elif defined(FML_ARCH_CPU_ARM64)
15+
#define kTargetArchitectureName "arm64"
16+
#elif defined(FML_ARCH_CPU_X86)
17+
#define kTargetArchitectureName "ia32"
18+
#elif defined(FML_ARCH_CPU_X86_64)
19+
#define kTargetArchitectureName "x64"
20+
#else
21+
#error Target architecture detection failed.
22+
#endif
23+
24+
#if defined(FML_OS_ANDROID)
25+
#define kTargetOperatingSystemName "android"
26+
#elif defined(OS_FUCHSIA)
27+
#define kTargetOperatingSystemName "fuchsia"
28+
#elif defined(FML_OS_LINUX)
29+
#define kTargetOperatingSystemName "linux"
30+
#elif defined(FML_OS_IOS) || defined(FML_OS_IOS_SIMULATOR)
31+
#define kTargetOperatingSystemName "ios"
32+
#elif defined(FML_OS_MACOSX)
33+
#define kTargetOperatingSystemName "macos"
34+
#elif defined(FML_OS_WIN)
35+
#define kTargetOperatingSystemName "windows"
36+
#else
37+
#error Target operating system detection failed.
38+
#endif
39+
40+
#define kTarget kTargetOperatingSystemName "_" kTargetArchitectureName
41+
42+
void NativeAssetsManager::RegisterNativeAssets(const uint8_t* manifest,
43+
size_t manifest_size) {
44+
parsed_mapping_.clear();
45+
46+
rapidjson::Document document;
47+
static_assert(sizeof(decltype(document)::Ch) == sizeof(uint8_t), "");
48+
document.Parse(reinterpret_cast<const decltype(document)::Ch*>(manifest),
49+
manifest_size);
50+
if (document.HasParseError()) {
51+
FML_DLOG(WARNING) << "NativeAssetsManifest.json is malformed.";
52+
return;
53+
}
54+
if (!document.IsObject()) {
55+
FML_DLOG(WARNING) << "NativeAssetsManifest.json is malformed.";
56+
return;
57+
}
58+
auto native_assets = document.FindMember("native-assets");
59+
if (native_assets == document.MemberEnd() ||
60+
!native_assets->value.IsObject()) {
61+
FML_DLOG(WARNING) << "NativeAssetsManifest.json is malformed.";
62+
return;
63+
}
64+
auto mapping = native_assets->value.FindMember(kTarget);
65+
if (mapping == native_assets->value.MemberEnd() ||
66+
!mapping->value.IsObject()) {
67+
FML_DLOG(WARNING) << "NativeAssetsManifest.json is malformed.";
68+
return;
69+
}
70+
for (auto entry = mapping->value.MemberBegin();
71+
entry != mapping->value.MemberEnd(); entry++) {
72+
std::vector<std::string> parsed_path;
73+
entry->name.GetString();
74+
auto& value = entry->value;
75+
if (!value.IsArray()) {
76+
FML_DLOG(WARNING) << "NativeAssetsManifest.json is malformed.";
77+
continue;
78+
}
79+
for (const auto& element : value.GetArray()) {
80+
if (!element.IsString()) {
81+
FML_DLOG(WARNING) << "NativeAssetsManifest.json is malformed.";
82+
continue;
83+
}
84+
parsed_path.push_back(element.GetString());
85+
}
86+
parsed_mapping_[entry->name.GetString()] = std::move(parsed_path);
87+
}
88+
}
89+
90+
void NativeAssetsManager::RegisterNativeAssets(
91+
const std::shared_ptr<AssetManager>& asset_manager) {
92+
std::unique_ptr<fml::Mapping> manifest_mapping =
93+
asset_manager->GetAsMapping("NativeAssetsManifest.json");
94+
if (manifest_mapping == nullptr) {
95+
FML_DLOG(WARNING)
96+
<< "Could not find NativeAssetsManifest.json in the asset store.";
97+
return;
98+
}
99+
100+
RegisterNativeAssets(manifest_mapping->GetMapping(),
101+
manifest_mapping->GetSize());
102+
}
103+
104+
std::vector<std::string> NativeAssetsManager::LookupNativeAsset(
105+
std::string_view asset_id) {
106+
// Cpp17 does not support unordered_map lookup with std::string_view on a
107+
// std::string key.
108+
std::string as_string = std::string(asset_id);
109+
if (parsed_mapping_.find(as_string) == parsed_mapping_.end()) {
110+
return std::vector<std::string>();
111+
}
112+
return parsed_mapping_[as_string];
113+
}
114+
115+
std::string NativeAssetsManager::AvailableNativeAssets() {
116+
if (parsed_mapping_.empty()) {
117+
return std::string("No available native assets.");
118+
}
119+
120+
std::string result;
121+
result.append("Available native assets: ");
122+
bool first = true;
123+
for (const auto& n : parsed_mapping_) {
124+
if (first) {
125+
first = false;
126+
} else {
127+
result.append(", ");
128+
}
129+
result.append(n.first);
130+
}
131+
132+
result.append(".");
133+
return result;
134+
}
135+
136+
} // namespace flutter

assets/native_assets.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#ifndef FLUTTER_ASSETS_NATIVE_ASSETS_H_
6+
#define FLUTTER_ASSETS_NATIVE_ASSETS_H_
7+
8+
#include <memory>
9+
#include <vector>
10+
11+
#include "flutter/assets/asset_manager.h"
12+
13+
namespace flutter {
14+
15+
// Parses the `NativeAssetsManifest.json` and provides a way to look up assets
16+
// and the available assets for the callbacks that are registered to the Dart VM
17+
// via the dart_api.h.
18+
//
19+
// The engine eagerly populates a native assets manager on startup. This native
20+
// assets manager is stored in the `IsolateGroupData` so it can be accessed on
21+
// the native assets callbacks registered in `InitDartFFIForIsolateGroup`.
22+
class NativeAssetsManager {
23+
public:
24+
NativeAssetsManager() = default;
25+
~NativeAssetsManager() = default;
26+
27+
// Reads the `NativeAssetsManifest.json` bundled in the Flutter application.
28+
void RegisterNativeAssets(const uint8_t* manifest, size_t manifest_size);
29+
void RegisterNativeAssets(const std::shared_ptr<AssetManager>& asset_manager);
30+
31+
// Looks up the asset path for [asset_id].
32+
//
33+
// The asset path consists of a type, and an optional path. For example:
34+
// `["system", "libsqlite3.so"]`.
35+
std::vector<std::string> LookupNativeAsset(std::string_view asset_id);
36+
37+
// Lists the available asset ids.
38+
//
39+
// Used when a user tries to look up an asset with an ID that does not exist
40+
// to report the list of available asset ids.
41+
std::string AvailableNativeAssets();
42+
43+
private:
44+
std::unordered_map<std::string, std::vector<std::string>> parsed_mapping_;
45+
46+
NativeAssetsManager(const NativeAssetsManager&) = delete;
47+
NativeAssetsManager(NativeAssetsManager&&) = delete;
48+
NativeAssetsManager& operator=(const NativeAssetsManager&) = delete;
49+
NativeAssetsManager& operator=(NativeAssetsManager&&) = delete;
50+
};
51+
52+
} // namespace flutter
53+
54+
#endif // FLUTTER_ASSETS_NATIVE_ASSETS_H_

assets/native_assets_unittests.cc

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/assets/native_assets.h"
6+
7+
#include "gtest/gtest.h"
8+
9+
namespace flutter {
10+
namespace testing {
11+
12+
// Manifest containing all hosts on which this test is run.
13+
// In practise, a manifest will only contain a single OS.
14+
// A manifest might contain multiple architectures if the OS supports
15+
// multi-arch apps.
16+
const char* kTestManifest = R"({
17+
"format-version": [
18+
1,
19+
0,
20+
0
21+
],
22+
"native-assets": {
23+
"linux_arm64": {
24+
"package:my_package/my_package_bindings_generated.dart": [
25+
"absolute",
26+
"libmy_package.so"
27+
]
28+
},
29+
"linux_x64": {
30+
"package:my_package/my_package_bindings_generated.dart": [
31+
"absolute",
32+
"libmy_package.so"
33+
]
34+
},
35+
"macos_arm64": {
36+
"package:my_package/my_package_bindings_generated.dart": [
37+
"absolute",
38+
"my_package.framework/my_package"
39+
]
40+
},
41+
"macos_x64": {
42+
"package:my_package/my_package_bindings_generated.dart": [
43+
"absolute",
44+
"my_package.framework/my_package"
45+
]
46+
},
47+
"windows_x64": {
48+
"package:my_package/my_package_bindings_generated.dart": [
49+
"absolute",
50+
"my_package.dll"
51+
]
52+
}
53+
}
54+
})";
55+
56+
TEST(NativeAssetsManagerTest, NoAvailableAssets) {
57+
NativeAssetsManager manager;
58+
std::string available_assets = manager.AvailableNativeAssets();
59+
ASSERT_EQ(available_assets, "No available native assets.");
60+
}
61+
62+
TEST(NativeAssetsManagerTest, NativeAssetsManifestParsing) {
63+
NativeAssetsManager manager;
64+
manager.RegisterNativeAssets(reinterpret_cast<const uint8_t*>(kTestManifest),
65+
strlen(kTestManifest));
66+
67+
std::string available_assets = manager.AvailableNativeAssets();
68+
ASSERT_EQ(available_assets,
69+
"Available native assets: "
70+
"package:my_package/my_package_bindings_generated.dart.");
71+
72+
std::vector<std::string> existing_asset = manager.LookupNativeAsset(
73+
"package:my_package/my_package_bindings_generated.dart");
74+
ASSERT_EQ(existing_asset.size(), 2u);
75+
ASSERT_EQ(existing_asset[0], "absolute");
76+
#if defined(FML_OS_MACOSX)
77+
ASSERT_EQ(existing_asset[1], "my_package.framework/my_package");
78+
#elif defined(FML_OS_LINUX)
79+
ASSERT_EQ(existing_asset[1], "libmy_package.so");
80+
#elif defined(FML_OS_WIN)
81+
ASSERT_EQ(existing_asset[1], "my_package.dll");
82+
#endif
83+
84+
std::vector<std::string> non_existing_asset =
85+
manager.LookupNativeAsset("non_existing_asset");
86+
ASSERT_EQ(non_existing_asset.size(), 0u);
87+
}
88+
89+
} // namespace testing
90+
} // namespace flutter

ci/licenses_golden/excluded_files

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
../../../flutter/Doxyfile
2525
../../../flutter/README.md
2626
../../../flutter/analysis_options.yaml
27+
../../../flutter/assets/native_assets_unittests.cc
2728
../../../flutter/build
2829
../../../flutter/build_overrides
2930
../../../flutter/buildtools

ci/licenses_golden/licenses_flutter

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42477,6 +42477,8 @@ ORIGIN: ../../../flutter/assets/asset_manager.h + ../../../flutter/LICENSE
4247742477
ORIGIN: ../../../flutter/assets/asset_resolver.h + ../../../flutter/LICENSE
4247842478
ORIGIN: ../../../flutter/assets/directory_asset_bundle.cc + ../../../flutter/LICENSE
4247942479
ORIGIN: ../../../flutter/assets/directory_asset_bundle.h + ../../../flutter/LICENSE
42480+
ORIGIN: ../../../flutter/assets/native_assets.cc + ../../../flutter/LICENSE
42481+
ORIGIN: ../../../flutter/assets/native_assets.h + ../../../flutter/LICENSE
4248042482
ORIGIN: ../../../flutter/benchmarking/benchmarking.cc + ../../../flutter/LICENSE
4248142483
ORIGIN: ../../../flutter/benchmarking/benchmarking.h + ../../../flutter/LICENSE
4248242484
ORIGIN: ../../../flutter/benchmarking/library.cc + ../../../flutter/LICENSE
@@ -45369,6 +45371,8 @@ FILE: ../../../flutter/assets/asset_manager.h
4536945371
FILE: ../../../flutter/assets/asset_resolver.h
4537045372
FILE: ../../../flutter/assets/directory_asset_bundle.cc
4537145373
FILE: ../../../flutter/assets/directory_asset_bundle.h
45374+
FILE: ../../../flutter/assets/native_assets.cc
45375+
FILE: ../../../flutter/assets/native_assets.h
4537245376
FILE: ../../../flutter/benchmarking/benchmarking.cc
4537345377
FILE: ../../../flutter/benchmarking/benchmarking.h
4537445378
FILE: ../../../flutter/benchmarking/library.cc

0 commit comments

Comments
 (0)