Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion assets/asset_resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class AssetResolver {
enum AssetResolverType {
kAssetManager,
kApkAssetProvider,
kDirectoryAssetBundle
kDirectoryAssetBundle,
kEmbedderAssetResolver
};

virtual bool IsValid() const = 0;
Expand Down
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,8 @@ FILE: ../../../flutter/shell/platform/embedder/assets/EmbedderInfo.plist
FILE: ../../../flutter/shell/platform/embedder/assets/embedder.modulemap
FILE: ../../../flutter/shell/platform/embedder/embedder.cc
FILE: ../../../flutter/shell/platform/embedder/embedder.h
FILE: ../../../flutter/shell/platform/embedder/embedder_asset_resolver.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_asset_resolver.h
FILE: ../../../flutter/shell/platform/embedder/embedder_engine.cc
FILE: ../../../flutter/shell/platform/embedder/embedder_engine.h
FILE: ../../../flutter/shell/platform/embedder/embedder_external_texture_gl.cc
Expand Down
2 changes: 2 additions & 0 deletions shell/platform/embedder/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ template("embedder_source_set") {
source_set(target_name) {
sources = [
"embedder.cc",
"embedder_asset_resolver.cc",
"embedder_asset_resolver.h",
"embedder_engine.cc",
"embedder_engine.h",
"embedder_external_texture_resolver.cc",
Expand Down
103 changes: 90 additions & 13 deletions shell/platform/embedder/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ extern const intptr_t kPlatformStrongDillSize;
#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_asset_resolver.h"
#include "flutter/shell/platform/embedder/embedder_engine.h"
#include "flutter/shell/platform/embedder/embedder_external_texture_resolver.h"
#include "flutter/shell/platform/embedder/embedder_platform_message_response.h"
Expand Down Expand Up @@ -926,10 +927,11 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
"The Flutter project arguments were missing.");
}

if (SAFE_ACCESS(args, assets_path, nullptr) == nullptr) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"The assets path in the Flutter project arguments was missing.");
if (SAFE_ACCESS(args, assets_path, nullptr) == nullptr &&
SAFE_ACCESS(args, asset_resolver, nullptr) == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"The assets path or asset resolver in the "
"Flutter project arguments was missing.");
}

if (SAFE_ACCESS(args, main_path__unused__, nullptr) != nullptr) {
Expand Down Expand Up @@ -987,19 +989,23 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
PopulateSnapshotMappingCallbacks(args, settings);

settings.icu_data_path = icu_data_path;
settings.assets_path = args->assets_path;
if (args->assets_path)
settings.assets_path = args->assets_path;
settings.leak_vm = !SAFE_ACCESS(args, shutdown_dart_vm_when_done, false);
settings.old_gen_heap_size = SAFE_ACCESS(args, dart_old_gen_heap_size, -1);

if (!flutter::DartVM::IsRunningPrecompiledCode()) {
// Verify the assets path contains Dart 2 kernel assets.
// NOTE: This check is skipped if using a custom asset resolver.
const std::string kApplicationKernelSnapshotFileName = "kernel_blob.bin";
std::string application_kernel_path = fml::paths::JoinPaths(
{settings.assets_path, kApplicationKernelSnapshotFileName});
if (!fml::IsFile(application_kernel_path)) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"Not running in AOT mode but could not resolve the kernel binary.");
if (args->assets_path) {
std::string application_kernel_path = fml::paths::JoinPaths(
{settings.assets_path, kApplicationKernelSnapshotFileName});
if (!fml::IsFile(application_kernel_path)) {
return LOG_EMBEDDER_ERROR(
kInvalidArguments,
"Not running in AOT mode but could not resolve the kernel binary.");
}
}
settings.application_kernel_asset = kApplicationKernelSnapshotFileName;
}
Expand Down Expand Up @@ -1296,8 +1302,38 @@ FlutterEngineResult FlutterEngineInitialize(size_t version,
"Task runner configuration was invalid.");
}

auto run_configuration =
flutter::RunConfiguration::InferFromSettings(settings);
auto asset_manager = std::make_shared<flutter::AssetManager>();

if (SAFE_ACCESS(args, asset_resolver, nullptr) != nullptr) {
auto resolver = args->asset_resolver;

auto user_data = SAFE_ACCESS(resolver, user_data, nullptr);
auto get_asset = SAFE_ACCESS(resolver, get_asset, nullptr);

if (get_asset == nullptr) {
return LOG_EMBEDDER_ERROR(kInvalidArguments,
"Asset Resolver get_asset is null.");
}

asset_manager->PushBack(
flutter::CreateEmbedderAssetResolver([=](const char* asset_name) {
FlutterMapping mapping = get_asset(asset_name, user_data);
return std::unique_ptr<fml::Mapping>(
reinterpret_cast<fml::Mapping*>(mapping));
}));
}

if (args->assets_path) {
asset_manager->PushBack(std::make_unique<flutter::DirectoryAssetBundle>(
fml::OpenDirectory(args->assets_path, false,
fml::FilePermission::kRead),
true));
}

auto run_configuration = flutter::RunConfiguration(
flutter::IsolateConfiguration::InferFromSettings(settings, asset_manager,
nullptr),
asset_manager);

if (SAFE_ACCESS(args, custom_dart_entrypoint, nullptr) != nullptr) {
auto dart_entrypoint = std::string{args->custom_dart_entrypoint};
Expand Down Expand Up @@ -2360,6 +2396,44 @@ FlutterEngineResult FlutterEngineNotifyDisplayUpdate(
}
}

FlutterEngineResult FlutterEngineCreateMapping(
const FlutterMappingCreateInfo* create_info,
FlutterMapping* out_mapping) {
auto data = SAFE_ACCESS(create_info, data, nullptr);
auto data_size = SAFE_ACCESS(create_info, data_size, 0);
if (data == nullptr && data_size > 0) {
return LOG_EMBEDDER_ERROR(kInvalidArguments, "Invalid mapping specified.");
}

auto user_data = SAFE_ACCESS(create_info, user_data, nullptr);
auto destruction_callback =
SAFE_ACCESS(create_info, destruction_callback, nullptr);

auto mapping = std::make_unique<fml::NonOwnedMapping>(
data, data_size,
[user_data, destruction_callback](const uint8_t* data, size_t size) {
if (destruction_callback) {
destruction_callback(data, size, user_data);
}
});

*out_mapping = reinterpret_cast<FlutterMapping>(mapping.release());

return kSuccess;
}

void FlutterEngineDestroyMapping(FlutterMapping mapping) {
delete reinterpret_cast<fml::Mapping*>(mapping);
}

const uint8_t* FlutterEngineGetMappingData(FlutterMapping mapping,
size_t* out_size) {
auto fml_mapping = reinterpret_cast<fml::Mapping*>(mapping);
if (out_size != nullptr)
*out_size = fml_mapping->GetSize();
return fml_mapping->GetMapping();
}

FlutterEngineResult FlutterEngineGetProcAddresses(
FlutterEngineProcTable* table) {
if (!table) {
Expand Down Expand Up @@ -2410,6 +2484,9 @@ FlutterEngineResult FlutterEngineGetProcAddresses(
SET_PROC(PostCallbackOnAllNativeThreads,
FlutterEnginePostCallbackOnAllNativeThreads);
SET_PROC(NotifyDisplayUpdate, FlutterEngineNotifyDisplayUpdate);
SET_PROC(CreateMapping, FlutterEngineCreateMapping);
SET_PROC(DestroyMapping, FlutterEngineDestroyMapping);
SET_PROC(GetMappingData, FlutterEngineGetMappingData);
#undef SET_PROC

return kSuccess;
Expand Down
144 changes: 144 additions & 0 deletions shell/platform/embedder/embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1345,12 +1345,90 @@ typedef void (*FlutterLogMessageCallback)(const char* /* tag */,
/// FlutterEngine instance in AOT mode.
typedef struct _FlutterEngineAOTData* FlutterEngineAOTData;

// Callback called by the Engine to destroy a previously created FlutterMapping.
//
// The callback may be called on any thread, so it must be thread-safe.
//
// The `data`, `data_size`, and `user_data` parameters are the same values
// passed in `FlutterEngineCreateMapping`.
typedef void (*FlutterMappingDestroyCallback)(const uint8_t* /* data */,
size_t /* data_size */,
void* /* user_data */);

/// An immutable buffer of potentially shared data.
typedef struct {
/// The size of the struct. Must be sizeof(FlutterMappingCreateInfo).
size_t struct_size;

/// A pointer to the data accessed by the Flutter Engine. The data will not be
/// mutated by the Flutter Engine, and must not be mutated by the Embedder
/// until the mapping is destroyed.
const uint8_t* data;
/// The size of the data backed by this mapping. The data must be valid for
/// reading until this point. Bytes past the end are undefined and not
/// accessed by the Engine.
size_t data_size;

/// An opaque baton passed back to the embedder when the destruction_callback
/// is invoked. The engine does not interpret this field in any way.
void* user_data;
/// Called once by the engine to destroy this mapping. The `data`,
/// `data_size`, and `user_data` are passed into the given callback. This call
/// may mutate/free/unmap the data, as it will no longer be accessed by the
/// Flutter Engine.
FlutterMappingDestroyCallback destruction_callback;
} FlutterMappingCreateInfo;

typedef struct FlutterMappingPrivate* FlutterMapping;

/// Callback for fetching assets for a `FlutterEngineAssetResolver`.
///
/// This may be called by multiple threads.
///
/// The `asset_name` parameter contains the path to the asset to load.
/// `user_data` is the user data from `FlutterEngineAssetResolver`, registered
/// via `FlutterProjectArgs`.
///
/// If the asset was found and successfully loaded, return a valid
/// `FlutterMapping`. Otherwise return NULL to indicate an error occurred
/// while loading the asset.
///
/// Note that the returned `FlutterMapping` is owned by the Engine and
/// shouldn't be cached or reused. Each callback invocation MUST return a new
/// FlutterMapping. Multiple mappings may refer to the same area in
/// memory, but proper book-keeping is up to the Embedder.
typedef FlutterMapping (*FlutterAssetResolverGetAssetCallback)(
const char* /* asset_name */,
void* /* user_data */);

/// Resolves assets on the behalf of the Flutter Engine, instead of accessing
/// the filesystem directly.
typedef struct {
/// The size of the struct. Must be sizeof(FlutterEngineAssetResolver).
size_t struct_size;

/// An opaque baton passed back to the embedder when a callback is
/// invoked. The engine does not interpret this field in any way.
void* user_data;

/// Required. Gets and returns an asset if available. See the documentation on
/// `FlutterAssetResolverGetAssetCallback` for more information.
FlutterAssetResolverGetAssetCallback get_asset;
} FlutterEngineAssetResolver;

typedef struct {
/// The size of this struct. Must be sizeof(FlutterProjectArgs).
size_t struct_size;
/// The path to the Flutter assets directory containing project assets. The
/// string can be collected after the call to `FlutterEngineRun` returns. The
/// string must be NULL terminated.
///
/// If `asset_resolver` is provided, may be NULL.
///
/// If both `asset_resolver` and `assets_path` are provided, the
/// `asset_resolver` comes first in the asset search order, then
/// `assets_path`. This effectively makes `asset_resolver` an overlay over
/// `assets_path`.
const char* assets_path;
/// The path to the Dart file containing the `main` entry point.
/// The string can be collected after the call to `FlutterEngineRun` returns.
Expand Down Expand Up @@ -1589,6 +1667,16 @@ typedef struct {
//
// The first argument is the `user_data` from `FlutterEngineInitialize`.
OnPreEngineRestartCallback on_pre_engine_restart_callback;

/// An asset resolver that fetches assets for the Engine.
///
/// If `assets_path` is provided, may be NULL.
///
/// If both `asset_resolver` and `assets_path` are provided, the
/// `asset_resolver` comes first in the asset search order, then
/// `assets_path`. This effectively makes `asset_resolver` an overlay over
/// `assets_path`.
const FlutterEngineAssetResolver* asset_resolver;
} FlutterProjectArgs;

#ifndef FLUTTER_ENGINE_NO_PROTOTYPES
Expand Down Expand Up @@ -2251,6 +2339,52 @@ FlutterEngineResult FlutterEngineNotifyDisplayUpdate(
const FlutterEngineDisplay* displays,
size_t display_count);

//------------------------------------------------------------------------------
/// @brief Creates a `FlutterMapping` using the given creation info.
/// The returned mapping is owned by the Embedder until passed to
/// the Engine.
///
/// When owned by the Engine:
///
/// The backing memory is never mutated by the Engine, and must not
/// be mutated by the Embedder until the mapping is destroyed.
/// The Engine may access the mapping from multiple threads, and may
/// destroy the mapping from any thread.
///
/// @param[in] create_info Struct describing the mapping to create.
/// @param[out] out_mapping The created mapping, if successful.
///
/// @return Whether the mapping was successfully created.
///
FLUTTER_EXPORT
FlutterEngineResult FlutterEngineCreateMapping(
const FlutterMappingCreateInfo* create_info,
FlutterMapping* out_mapping);

//------------------------------------------------------------------------------
/// @brief Destroys a `FlutterMapping` owned by the Embedder.
/// This may be called by any thread, as long as the Engine doesn't
/// own the mapping.
///
/// @param[in] mapping The mapping owned by the Embedder to destroy.
///
FLUTTER_EXPORT
void FlutterEngineDestroyMapping(FlutterMapping mapping);

//------------------------------------------------------------------------------
/// @brief Gets the data and size of a `FlutterMapping`.
/// The mapping must be owned by the Embedder.
///
/// @param[in] mapping The mapping to get the data and size of.
/// @param[out] out_size Returns the mapping's size, if provided.
/// May be NULL.
///
/// @return The address to the mapping's data.
///
FLUTTER_EXPORT
const uint8_t* FlutterEngineGetMappingData(FlutterMapping mapping,
size_t* out_size);

#endif // !FLUTTER_ENGINE_NO_PROTOTYPES

// Typedefs for the function pointers in FlutterEngineProcTable.
Expand Down Expand Up @@ -2367,6 +2501,13 @@ typedef FlutterEngineResult (*FlutterEngineNotifyDisplayUpdateFnPtr)(
FlutterEngineDisplaysUpdateType update_type,
const FlutterEngineDisplay* displays,
size_t display_count);
typedef FlutterEngineResult (*FlutterEngineCreateMappingFnPtr)(
const FlutterMappingCreateInfo* create_info,
FlutterMapping* out_mapping);
typedef void (*FlutterEngineDestroyMappingFnPtr)(FlutterMapping mapping);
typedef const uint8_t* (*FlutterEngineGetMappingDataFnPtr)(
FlutterMapping mapping,
size_t* out_size);

/// Function-pointer-based versions of the APIs above.
typedef struct {
Expand Down Expand Up @@ -2411,6 +2552,9 @@ typedef struct {
FlutterEnginePostCallbackOnAllNativeThreadsFnPtr
PostCallbackOnAllNativeThreads;
FlutterEngineNotifyDisplayUpdateFnPtr NotifyDisplayUpdate;
FlutterEngineCreateMappingFnPtr CreateMapping;
FlutterEngineDestroyMappingFnPtr DestroyMapping;
FlutterEngineGetMappingDataFnPtr GetMappingData;
} FlutterEngineProcTable;

//------------------------------------------------------------------------------
Expand Down
Loading