Flutter Engine
The Flutter Engine
native_assets_api_impl.cc
Go to the documentation of this file.
1// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
6
7#include "platform/globals.h"
8#include "platform/utils.h"
9
10#if defined(DART_HOST_OS_WINDOWS)
11#include <Psapi.h>
12#include <Windows.h>
13#include <combaseapi.h>
14#include <stdio.h>
15#include <tchar.h>
16#endif
17#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
18 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
19#include <dlfcn.h>
20#endif
21
22#include "bin/file.h"
23#include "platform/uri.h"
24
25namespace dart {
26namespace bin {
27
28#define SET_ERROR_MSG(error_msg, format, ...) \
29 intptr_t len = snprintf(nullptr, 0, format, __VA_ARGS__); \
30 char* msg = reinterpret_cast<char*>(malloc(len + 1)); \
31 snprintf(msg, len + 1, format, __VA_ARGS__); \
32 *error_msg = msg
33
34#if defined(DART_TARGET_OS_WINDOWS)
35// Replaces back slashes with forward slashes in place.
36static void ReplaceBackSlashes(char* cstr) {
37 const intptr_t length = strlen(cstr);
38 for (int i = 0; i < length; i++) {
39 cstr[i] = cstr[i] == '\\' ? '/' : cstr[i];
40 }
41}
42#endif
43
44const char* file_schema = "file://";
45const int file_schema_length = 7;
46
47// Get a file uri with only forward slashes from the script path.
48// Returned string must be freed by caller.
49CStringUniquePtr CleanScriptUri(const char* script_uri) {
51
52 if (strlen(script_uri) > file_schema_length &&
53 strncmp(script_uri, file_schema, file_schema_length) == 0) {
54 // Isolate.spawnUri sets a `source` including the file schema,
55 // e.g. Isolate.spawnUri may make the embedder pass a file:// uri.
56 script_path = File::UriToPath(script_uri);
57 } else {
58 // Dart and Flutter embedders set a source without a file schema.
59 script_path = CStringUniquePtr(strdup(script_uri));
60 }
61
62 // Resolve symlinks.
63 char canon_path[PATH_MAX];
64 File::GetCanonicalPath(nullptr, script_path.get(), canon_path, PATH_MAX);
65
66 // Convert path to Uri. Inspired by sdk/lib/core/uri.dart _makeFileUri.
67 // Only has a single case, the path is always absolute and always a file.
68 const intptr_t len = strlen(canon_path);
69 char* path_copy =
70 reinterpret_cast<char*>(malloc(file_schema_length + len + 1));
71 snprintf(path_copy, len + 1, "%s%s", file_schema, canon_path);
72#if defined(DART_TARGET_OS_WINDOWS)
73 // Replace backward slashes with forward slashes.
74 ReplaceBackSlashes(path_copy);
75#endif
77}
78
79// If an error occurs populates |error| (if provided) with an error message
80// (caller must free this message when it is no longer needed).
81static void* LoadDynamicLibrary(const char* library_file,
82 char** error = nullptr) {
83 char* utils_error = nullptr;
84 void* handle = Utils::LoadDynamicLibrary(library_file, &utils_error);
85 if (utils_error != nullptr) {
86 if (error != nullptr) {
87 SET_ERROR_MSG(error, "Failed to load dynamic library '%s': %s",
88 library_file != nullptr ? library_file : "<process>",
89 utils_error);
90 }
91 free(utils_error);
92 }
93 return handle;
94}
95
96#if defined(DART_HOST_OS_WINDOWS)
97// On windows, nullptr signals trying a lookup in all loaded modules.
98const nullptr_t kWindowsDynamicLibraryProcessPtr = nullptr;
99#endif
100
101static void WrapError(const char* path, char** error) {
102 if (*error != nullptr) {
103 char* inner_error = *error;
104 SET_ERROR_MSG(error, "Failed to load dynamic library '%s': %s", path,
105 inner_error);
106 free(inner_error);
107 }
108}
109
110static void WrapErrorRelative(const char* path,
111 const char* script_uri,
112 char** error) {
113 if (*error != nullptr) {
114 char* inner_error = *error;
116 "Failed to load dynamic library '%s' relative to '%s': %s",
117 path, script_uri, inner_error);
118 free(inner_error);
119 }
120}
121
122void* NativeAssets::DlopenAbsolute(const char* path, char** error) {
123 // If we'd want to be strict, it should not take into account include paths.
124 void* handle = LoadDynamicLibrary(path, error);
126 return handle;
127}
128
130 const char* script_uri,
131 char** error) {
132 void* handle = nullptr;
133 CStringUniquePtr platform_script_cstr = CleanScriptUri(script_uri);
134 const intptr_t len = strlen(path);
135 char* path_copy = reinterpret_cast<char*>(malloc(len + 1));
136 snprintf(path_copy, len + 1, "%s", path);
137#if defined(DART_TARGET_OS_WINDOWS)
138 ReplaceBackSlashes(path_copy);
139#endif
140 auto target_uri = ResolveUri(path_copy, platform_script_cstr.get());
141 if (!target_uri) {
142 SET_ERROR_MSG(error, "Failed to resolve '%s' relative to '%s'.", path_copy,
143 platform_script_cstr.get());
144 } else {
145 const char* target_path = target_uri.get() + file_schema_length;
146 handle = LoadDynamicLibrary(target_path, error);
147 }
148 free(path_copy);
149 WrapErrorRelative(path, script_uri, error);
150 return handle;
151}
152
153void* NativeAssets::DlopenSystem(const char* path, char** error) {
154 // Should take into account LD_PATH etc.
155 void* handle = LoadDynamicLibrary(path, error);
157 return handle;
158}
159
161#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
162 defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA)
163 return RTLD_DEFAULT;
164#else
165 return kWindowsDynamicLibraryProcessPtr;
166#endif
167}
168
170 return LoadDynamicLibrary(nullptr, error);
171}
172
173#if defined(DART_HOST_OS_WINDOWS)
174void* co_task_mem_allocated = nullptr;
175
176// If an error occurs populates |error| with an error message
177// (caller must free this message when it is no longer needed).
178void* LookupSymbolInProcess(const char* symbol, char** error) {
179 // Force loading ole32.dll.
180 if (co_task_mem_allocated == nullptr) {
181 co_task_mem_allocated = CoTaskMemAlloc(sizeof(intptr_t));
182 CoTaskMemFree(co_task_mem_allocated);
183 }
184
185 HANDLE current_process =
186 OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE,
188 if (current_process == nullptr) {
189 SET_ERROR_MSG(error, "Failed to open current process.");
190 return nullptr;
191 }
192
193 HMODULE modules[1024];
194 DWORD cb_needed;
195 if (EnumProcessModules(current_process, modules, sizeof(modules),
196 &cb_needed) != 0) {
197 for (intptr_t i = 0; i < (cb_needed / sizeof(HMODULE)); i++) {
198 if (auto result =
199 reinterpret_cast<void*>(GetProcAddress(modules[i], symbol))) {
200 CloseHandle(current_process);
201 return result;
202 }
203 }
204 }
205 CloseHandle(current_process);
206
208 error, "None of the loaded modules contained the requested symbol '%s'.",
209 symbol);
210 return nullptr;
211}
212#endif
213
214// If an error occurs populates |error| with an error message
215// (caller must free this message when it is no longer needed).
216static void* ResolveSymbol(void* handle, const char* symbol, char** error) {
217#if defined(DART_HOST_OS_WINDOWS)
218 if (handle == kWindowsDynamicLibraryProcessPtr) {
219 return LookupSymbolInProcess(symbol, error);
220 }
221#endif
222 return Utils::ResolveSymbolInDynamicLibrary(handle, symbol, error);
223}
224
225void* NativeAssets::Dlsym(void* handle, const char* symbol, char** error) {
226 void* const result = ResolveSymbol(handle, symbol, error);
227 if (*error != nullptr) {
228 char* inner_error = *error;
229 SET_ERROR_MSG(error, "Failed to lookup symbol '%s': %s", symbol,
230 inner_error);
231 free(inner_error);
232 }
233 return result;
234}
235
236} // namespace bin
237} // namespace dart
static void * LoadDynamicLibrary(const char *library_path, char **error=nullptr)
Definition: utils.cc:289
static void * ResolveSymbolInDynamicLibrary(void *library_handle, const char *symbol, char **error=nullptr)
Definition: utils.cc:322
static const char * GetCanonicalPath(Namespace *namespc, const char *path, char *dest=nullptr, int dest_size=0)
static CStringUniquePtr UriToPath(const char *uri)
static void * DlopenSystem(const char *path, char **error)
static void * DlopenExecutable(char **error)
static void * DlopenProcess(char **error)
static void * DlopenRelative(const char *path, const char *script_uri, char **error)
static void * Dlsym(void *handle, const char *symbol, char **error)
static void * DlopenAbsolute(const char *path, char **error)
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
size_t length
return FALSE
static void WrapError(const char *path, char **error)
static void * LoadDynamicLibrary(const char *library_file, char **error=nullptr)
const char * file_schema
const int file_schema_length
CStringUniquePtr CleanScriptUri(const char *script_uri)
static void * ResolveSymbol(void *handle, const char *symbol, char **error)
static void WrapErrorRelative(const char *path, const char *script_uri, char **error)
Definition: dart_vm.cc:33
CAllocUniquePtr< char > CStringUniquePtr
Definition: utils.h:31
void * malloc(size_t size)
Definition: allocation.cc:19
CStringUniquePtr ResolveUri(const char *ref_uri, const char *base_uri)
Definition: uri.cc:432
static zx_koid_t GetCurrentProcessId()
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
char * strdup(const char *str1)
#define SET_ERROR_MSG(error_msg, format,...)
SKWASM_EXPORT SkPath * path_copy(SkPath *path)
Definition: path.cpp:20
#define PATH_MAX
Definition: globals.h:708
void * HANDLE
Definition: windows_types.h:36
unsigned long DWORD
Definition: windows_types.h:22
HINSTANCE HMODULE
Definition: windows_types.h:96