Flutter Engine
The Flutter Engine
immutable_buffer.cc
Go to the documentation of this file.
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/lib/ui/painting/immutable_buffer.h"
6
7#include <cstring>
8
9#include "flutter/fml/file.h"
10#include "flutter/fml/make_copyable.h"
11#include "flutter/lib/ui/ui_dart_state.h"
12#include "flutter/lib/ui/window/platform_configuration.h"
17
18#if FML_OS_ANDROID
19#include <sys/mman.h>
20#endif
21
22namespace flutter {
23
25
27
30 Dart_Handle callback_handle) {
31 if (!Dart_IsClosure(callback_handle)) {
32 return tonic::ToDart("Callback must be a function");
33 }
34
35 tonic::Uint8List dataList = tonic::Uint8List(data);
36
37 auto sk_data = MakeSkDataWithCopy(dataList.data(), dataList.num_elements());
38 dataList.Release();
39 auto buffer = fml::MakeRefCounted<ImmutableBuffer>(sk_data);
40 buffer->AssociateWithDartWrapper(buffer_handle);
41 tonic::DartInvoke(callback_handle, {Dart_TypeVoid()});
42
43 return Dart_Null();
44}
45
47 Dart_Handle asset_name_handle,
48 Dart_Handle callback_handle) {
50 if (!Dart_IsClosure(callback_handle)) {
51 return tonic::ToDart("Callback must be a function");
52 }
53
54 uint8_t* chars = nullptr;
55 intptr_t asset_length = 0;
57 Dart_StringToUTF8(asset_name_handle, &chars, &asset_length);
58 if (Dart_IsError(result)) {
59 return tonic::ToDart("Asset name must be valid UTF8");
60 }
61
62 std::string asset_name = std::string{reinterpret_cast<const char*>(chars),
63 static_cast<size_t>(asset_length)};
64
65 auto* dart_state = UIDartState::Current();
66 auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner();
67 auto* buffer_callback_ptr =
68 new tonic::DartPersistentValue(dart_state, callback_handle);
69 auto* buffer_handle_ptr =
70 new tonic::DartPersistentValue(dart_state, raw_buffer_handle);
71 auto asset_manager = UIDartState::Current()
73 ->client()
75
76 auto ui_task = fml::MakeCopyable(
77 [buffer_callback_ptr, buffer_handle_ptr](const sk_sp<SkData>& sk_data,
78 size_t buffer_size) mutable {
79 std::unique_ptr<tonic::DartPersistentValue> buffer_handle(
80 buffer_handle_ptr);
81 std::unique_ptr<tonic::DartPersistentValue> buffer_callback(
82 buffer_callback_ptr);
83
84 auto dart_state = buffer_callback->dart_state().lock();
85 if (!dart_state) {
86 return;
87 }
88 tonic::DartState::Scope scope(dart_state);
89
90 if (!sk_data) {
91 // -1 is used as a sentinel that the file could not be opened.
92 tonic::DartInvoke(buffer_callback->Get(), {tonic::ToDart(-1)});
93 return;
94 }
95 auto buffer = fml::MakeRefCounted<ImmutableBuffer>(sk_data);
96 buffer->AssociateWithDartWrapper(buffer_handle->Get());
97 tonic::DartInvoke(buffer_callback->Get(), {tonic::ToDart(buffer_size)});
98 });
99
100 dart_state->GetConcurrentTaskRunner()->PostTask(
101 [asset_name = std::move(asset_name),
102 asset_manager = std::move(asset_manager),
103 ui_task_runner = std::move(ui_task_runner), ui_task] {
104 std::unique_ptr<fml::Mapping> mapping =
105 asset_manager->GetAsMapping(asset_name);
106
107 sk_sp<SkData> sk_data;
108 size_t buffer_size = 0;
109 if (mapping != nullptr) {
110 buffer_size = mapping->GetSize();
111 const void* bytes = static_cast<const void*>(mapping->GetMapping());
112 sk_data = MakeSkDataWithCopy(bytes, buffer_size);
113 }
114 ui_task_runner->PostTask(
115 [sk_data = std::move(sk_data), ui_task = ui_task, buffer_size]() {
116 ui_task(sk_data, buffer_size);
117 });
118 });
119 return Dart_Null();
120}
121
123 Dart_Handle file_path_handle,
124 Dart_Handle callback_handle) {
126 if (!Dart_IsClosure(callback_handle)) {
127 return tonic::ToDart("Callback must be a function");
128 }
129
130 uint8_t* chars = nullptr;
131 intptr_t file_path_length = 0;
133 Dart_StringToUTF8(file_path_handle, &chars, &file_path_length);
134 if (Dart_IsError(result)) {
135 return tonic::ToDart("File path must be valid UTF8");
136 }
137
138 std::string file_path = std::string{reinterpret_cast<const char*>(chars),
139 static_cast<size_t>(file_path_length)};
140
141 auto* dart_state = UIDartState::Current();
142 auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner();
143 auto* buffer_callback_ptr =
144 new tonic::DartPersistentValue(dart_state, callback_handle);
145 auto* buffer_handle_ptr =
146 new tonic::DartPersistentValue(dart_state, raw_buffer_handle);
147
148 auto ui_task = fml::MakeCopyable(
149 [buffer_callback_ptr, buffer_handle_ptr](const sk_sp<SkData>& sk_data,
150 size_t buffer_size) mutable {
151 std::unique_ptr<tonic::DartPersistentValue> buffer_handle(
152 buffer_handle_ptr);
153 std::unique_ptr<tonic::DartPersistentValue> buffer_callback(
154 buffer_callback_ptr);
155 auto dart_state = buffer_callback->dart_state().lock();
156 if (!dart_state) {
157 return;
158 }
159 tonic::DartState::Scope scope(dart_state);
160
161 if (!sk_data) {
162 // -1 is used as a sentinel that the file could not be opened.
163 tonic::DartInvoke(buffer_callback->Get(), {tonic::ToDart(-1)});
164 return;
165 }
166 auto buffer = fml::MakeRefCounted<ImmutableBuffer>(sk_data);
167 buffer->AssociateWithDartWrapper(buffer_handle->Get());
168 tonic::DartInvoke(buffer_callback->Get(), {tonic::ToDart(buffer_size)});
169 });
170
171 dart_state->GetConcurrentTaskRunner()->PostTask(
172 [file_path = std::move(file_path),
173 ui_task_runner = std::move(ui_task_runner), ui_task] {
174 auto mapping = std::make_unique<fml::FileMapping>(fml::OpenFile(
175 file_path.c_str(), false, fml::FilePermission::kRead));
176
177 sk_sp<SkData> sk_data;
178 size_t buffer_size = 0;
179 if (mapping->IsValid()) {
180 buffer_size = mapping->GetSize();
181 const void* bytes = static_cast<const void*>(mapping->GetMapping());
182 sk_data = MakeSkDataWithCopy(bytes, buffer_size);
183 }
184 ui_task_runner->PostTask(
185 [sk_data = std::move(sk_data), ui_task = ui_task, buffer_size]() {
186 ui_task(sk_data, buffer_size);
187 });
188 });
189 return Dart_Null();
190}
191
192#if FML_OS_ANDROID
193
194// Compressed image buffers are allocated on the UI thread but are deleted on a
195// decoder worker thread. Android's implementation of malloc appears to
196// continue growing the native heap size when the allocating thread is
197// different from the freeing thread. To work around this, create an SkData
198// backed by an anonymous mapping.
199sk_sp<SkData> ImmutableBuffer::MakeSkDataWithCopy(const void* data,
200 size_t length) {
201 if (length == 0) {
202 return SkData::MakeEmpty();
203 }
204
205 size_t mapping_length = length + sizeof(size_t);
206 void* mapping = ::mmap(nullptr, mapping_length, PROT_READ | PROT_WRITE,
207 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
208
209 if (mapping == MAP_FAILED) {
210 return SkData::MakeEmpty();
211 }
212
213 *reinterpret_cast<size_t*>(mapping) = mapping_length;
214 void* mapping_data = reinterpret_cast<char*>(mapping) + sizeof(size_t);
215 ::memcpy(mapping_data, data, length);
216
217 SkData::ReleaseProc proc = [](const void* ptr, void* context) {
218 size_t* size_ptr = reinterpret_cast<size_t*>(context);
219 FML_DCHECK(ptr == size_ptr + 1);
220 if (::munmap(const_cast<void*>(context), *size_ptr) == -1) {
221 FML_LOG(ERROR) << "munmap of codec SkData failed";
222 }
223 };
224
225 return SkData::MakeWithProc(mapping_data, length, proc, mapping);
226}
227
228#else
229
230sk_sp<SkData> ImmutableBuffer::MakeSkDataWithCopy(const void* data,
231 size_t length) {
233}
234
235#endif // FML_OS_ANDROID
236
237} // namespace flutter
static uint32_t buffer_size(uint32_t offset, uint32_t maxAlignment)
void(* ReleaseProc)(const void *ptr, void *context)
Definition: SkData.h:78
static sk_sp< SkData > MakeWithProc(const void *ptr, size_t length, ReleaseProc proc, void *ctx)
Definition: SkData.cpp:128
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition: SkData.cpp:111
static sk_sp< SkData > MakeEmpty()
Definition: SkData.cpp:94
sk_sp< SkData > data() const
Callers should not modify the returned data. This is not exposed to Dart.
static Dart_Handle initFromAsset(Dart_Handle buffer_handle, Dart_Handle asset_name_handle, Dart_Handle callback_handle)
static Dart_Handle init(Dart_Handle buffer_handle, Dart_Handle data, Dart_Handle callback_handle)
size_t length() const
The length of the data in bytes.
static Dart_Handle initFromFile(Dart_Handle buffer_handle, Dart_Handle file_path_handle, Dart_Handle callback_handle)
virtual std::shared_ptr< AssetManager > GetAssetManager()=0
Returns the current collection of assets available on the platform.
PlatformConfigurationClient * client() const
Access to the platform configuration client (which typically is implemented by the RuntimeController)...
PlatformConfiguration * platform_configuration() const
static UIDartState * Current()
static void ThrowIfUIOperationsProhibited()
void AssociateWithDartWrapper(Dart_Handle wrappable)
DART_EXPORT Dart_Handle Dart_TypeVoid(void)
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
DART_EXPORT Dart_Handle Dart_Null(void)
DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str, uint8_t **utf8_array, intptr_t *length)
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT bool Dart_IsClosure(Dart_Handle object)
GAsyncResult * result
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_DCHECK(condition)
Definition: logging.h:103
size_t length
IMPLEMENT_WRAPPERTYPEINFO(flutter_gpu, FlutterGpuTestClass)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition: switches.h:41
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 to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
internal::CopyableLambda< T > MakeCopyable(T lambda)
Definition: make_copyable.h:57
fml::UniqueFD OpenFile(const char *path, bool create_if_necessary, FilePermission permission)
This can open a directory on POSIX, but not on Windows.
Definition: file_posix.cc:66
Dart_Handle ToDart(const T &object)
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
Definition: dart_invoke.cc:20
#define ERROR(message)
Definition: elf_loader.cc:260