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/lib/ui/ui_dart_state.h"
13 
14 #if OS_ANDROID
15 #include <sys/mman.h>
16 #endif
17 
18 namespace flutter {
19 
20 IMPLEMENT_WRAPPERTYPEINFO(ui, ImmutableBuffer);
21 
22 #define FOR_EACH_BINDING(V) \
23  V(ImmutableBuffer, dispose) \
24  V(ImmutableBuffer, length)
25 
27 
29 
31  natives->Register({{"ImmutableBuffer_init", ImmutableBuffer::init, 3, true},
33 }
34 
35 void ImmutableBuffer::init(Dart_NativeArguments args) {
36  Dart_Handle callback_handle = Dart_GetNativeArgument(args, 2);
37  if (!Dart_IsClosure(callback_handle)) {
38  Dart_SetReturnValue(args, tonic::ToDart("Callback must be a function"));
39  return;
40  }
41 
42  Dart_Handle buffer_handle = Dart_GetNativeArgument(args, 0);
43  tonic::Uint8List data = tonic::Uint8List(Dart_GetNativeArgument(args, 1));
44 
45  auto sk_data = MakeSkDataWithCopy(data.data(), data.num_elements());
46  data.Release();
47  auto buffer = fml::MakeRefCounted<ImmutableBuffer>(sk_data);
48  buffer->AssociateWithDartWrapper(buffer_handle);
49  tonic::DartInvoke(callback_handle, {Dart_TypeVoid()});
50 }
51 
53  return sizeof(ImmutableBuffer) + data_->size();
54 }
55 
56 #if OS_ANDROID
57 
58 // Compressed image buffers are allocated on the UI thread but are deleted on a
59 // decoder worker thread. Android's implementation of malloc appears to
60 // continue growing the native heap size when the allocating thread is
61 // different from the freeing thread. To work around this, create an SkData
62 // backed by an anonymous mapping.
63 sk_sp<SkData> ImmutableBuffer::MakeSkDataWithCopy(const void* data,
64  size_t length) {
65  if (length == 0) {
66  return SkData::MakeEmpty();
67  }
68 
69  size_t mapping_length = length + sizeof(size_t);
70  void* mapping = ::mmap(nullptr, mapping_length, PROT_READ | PROT_WRITE,
71  MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
72 
73  if (mapping == MAP_FAILED) {
74  return SkData::MakeEmpty();
75  }
76 
77  *reinterpret_cast<size_t*>(mapping) = mapping_length;
78  void* mapping_data = reinterpret_cast<char*>(mapping) + sizeof(size_t);
79  ::memcpy(mapping_data, data, length);
80 
81  SkData::ReleaseProc proc = [](const void* ptr, void* context) {
82  size_t* size_ptr = reinterpret_cast<size_t*>(context);
83  FML_DCHECK(ptr == size_ptr + 1);
84  if (::munmap(const_cast<void*>(context), *size_ptr) == -1) {
85  FML_LOG(ERROR) << "munmap of codec SkData failed";
86  }
87  };
88 
89  return SkData::MakeWithProc(mapping_data, length, proc, mapping);
90 }
91 
92 #else
93 
94 sk_sp<SkData> ImmutableBuffer::MakeSkDataWithCopy(const void* data,
95  size_t length) {
96  return SkData::MakeWithCopy(data, length);
97 }
98 
99 #endif // OS_ANDROID
100 
101 } // namespace flutter
sk_sp< SkData > data() const
Callers should not modify the returned data. This is not exposed to Dart.
#define FML_DCHECK(condition)
Definition: logging.h:86
#define FML_LOG(severity)
Definition: logging.h:65
#define DART_NATIVE_CALLBACK(CLASS, METHOD)
Dart_Handle DartInvoke(Dart_Handle closure, std::initializer_list< Dart_Handle > args)
Definition: dart_invoke.cc:20
IMPLEMENT_WRAPPERTYPEINFO(ui, Scene)
#define FOR_EACH_BINDING(V)
static void RegisterNatives(tonic::DartLibraryNatives *natives)
void Register(std::initializer_list< Entry > entries)
static void init(Dart_NativeArguments args)
size_t length() const
The length of the data in bytes.
size_t GetAllocationSize() const override
#define DART_REGISTER_NATIVE(CLASS, METHOD)
Dart_Handle ToDart(const T &object)