Flutter Engine
callback_cache.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/plugins/callback_cache.h"
6 
7 #include <fstream>
8 #include <iterator>
9 
10 #include "flutter/fml/build_config.h"
11 #include "flutter/fml/logging.h"
12 #include "flutter/fml/paths.h"
13 #include "rapidjson/document.h"
14 #include "rapidjson/stringbuffer.h"
15 #include "rapidjson/writer.h"
17 
18 using rapidjson::Document;
19 using rapidjson::StringBuffer;
20 using rapidjson::Writer;
21 using tonic::ToDart;
22 
23 namespace flutter {
24 
25 static const char* kHandleKey = "handle";
26 static const char* kRepresentationKey = "representation";
27 static const char* kNameKey = "name";
28 static const char* kClassNameKey = "class_name";
29 static const char* kLibraryPathKey = "library_path";
30 static const char* kCacheName = "flutter_callback_cache.json";
31 std::mutex DartCallbackCache::mutex_;
32 std::string DartCallbackCache::cache_path_;
33 std::map<int64_t, DartCallbackRepresentation> DartCallbackCache::cache_;
34 
35 void DartCallbackCache::SetCachePath(const std::string& path) {
36  cache_path_ = fml::paths::JoinPaths({path, kCacheName});
37 }
38 
39 Dart_Handle DartCallbackCache::GetCallback(int64_t handle) {
40  std::scoped_lock lock(mutex_);
41  auto iterator = cache_.find(handle);
42  if (iterator != cache_.end()) {
43  DartCallbackRepresentation cb = iterator->second;
44  return LookupDartClosure(cb.name, cb.class_name, cb.library_path);
45  }
46  return Dart_Null();
47 }
48 
49 int64_t DartCallbackCache::GetCallbackHandle(const std::string& name,
50  const std::string& class_name,
51  const std::string& library_path) {
52  std::scoped_lock lock(mutex_);
53  std::hash<std::string> hasher;
54  int64_t hash = hasher(name);
55  hash += hasher(class_name);
56  hash += hasher(library_path);
57 
58  if (cache_.find(hash) == cache_.end()) {
59  cache_[hash] = {name, class_name, library_path};
60  SaveCacheToDisk();
61  }
62  return hash;
63 }
64 
65 std::unique_ptr<DartCallbackRepresentation>
67  std::scoped_lock lock(mutex_);
68  auto iterator = cache_.find(handle);
69  if (iterator != cache_.end()) {
70  return std::make_unique<DartCallbackRepresentation>(iterator->second);
71  }
72  return nullptr;
73 }
74 
75 void DartCallbackCache::SaveCacheToDisk() {
76  // Cache JSON format
77  // [
78  // {
79  // "hash": 42,
80  // "representation": {
81  // "name": "...",
82  // "class_name": "...",
83  // "library_path": "..."
84  // }
85  // },
86  // {
87  // ...
88  // }
89  // ]
90  StringBuffer s;
91  Writer<StringBuffer> writer(s);
92  writer.StartArray();
93  for (auto iterator = cache_.begin(); iterator != cache_.end(); ++iterator) {
94  int64_t hash = iterator->first;
95  DartCallbackRepresentation cb = iterator->second;
96  writer.StartObject();
97  writer.Key(kHandleKey);
98  writer.Int64(hash);
99  writer.Key(kRepresentationKey);
100  writer.StartObject();
101  writer.Key(kNameKey);
102  writer.String(cb.name.c_str());
103  writer.Key(kClassNameKey);
104  writer.String(cb.class_name.c_str());
105  writer.Key(kLibraryPathKey);
106  writer.String(cb.library_path.c_str());
107  writer.EndObject();
108  writer.EndObject();
109  }
110  writer.EndArray();
111 
112  std::ofstream output(cache_path_);
113  output << s.GetString();
114  output.close();
115 }
116 
118  std::scoped_lock lock(mutex_);
119 
120  // Don't reload the cache if it's already populated.
121  if (!cache_.empty()) {
122  return;
123  }
124  std::ifstream input(cache_path_);
125  if (!input) {
126  return;
127  }
128  std::string cache_contents{std::istreambuf_iterator<char>(input),
129  std::istreambuf_iterator<char>()};
130  Document d;
131  d.Parse(cache_contents.c_str());
132  if (d.HasParseError() || !d.IsArray()) {
133  FML_LOG(INFO) << "Could not parse callback cache, aborting restore";
134  // TODO(bkonyi): log and bail (delete cache?)
135  return;
136  }
137  const auto entries = d.GetArray();
138  for (auto* it = entries.begin(); it != entries.end(); ++it) {
139  const auto root_obj = it->GetObject();
140  const auto representation = root_obj[kRepresentationKey].GetObject();
141 
142  const int64_t hash = root_obj[kHandleKey].GetInt64();
144  cb.name = representation[kNameKey].GetString();
145  cb.class_name = representation[kClassNameKey].GetString();
146  cb.library_path = representation[kLibraryPathKey].GetString();
147  cache_[hash] = cb;
148  }
149 }
150 
151 Dart_Handle DartCallbackCache::LookupDartClosure(
152  const std::string& name,
153  const std::string& class_name,
154  const std::string& library_path) {
155  Dart_Handle closure_name = ToDart(name);
156  if (Dart_IsError(closure_name)) {
157  return closure_name;
158  }
159  Dart_Handle library_name =
160  library_path.empty() ? Dart_Null() : ToDart(library_path);
161  if (Dart_IsError(library_name)) {
162  return library_name;
163  }
164  Dart_Handle cls_name = class_name.empty() ? Dart_Null() : ToDart(class_name);
165  if (Dart_IsError(cls_name)) {
166  return cls_name;
167  }
168 
169  Dart_Handle library;
170  if (library_name == Dart_Null()) {
171  library = Dart_RootLibrary();
172  } else {
173  library = Dart_LookupLibrary(library_name);
174  }
175  if (Dart_IsError(library)) {
176  return library;
177  }
178 
179  Dart_Handle closure;
180  if (Dart_IsNull(cls_name)) {
181  closure = Dart_GetField(library, closure_name);
182  } else {
183  Dart_Handle cls = Dart_GetClass(library, cls_name);
184  if (Dart_IsError(cls)) {
185  return cls;
186  }
187  if (Dart_IsNull(cls)) {
188  closure = Dart_Null();
189  } else {
190  closure = Dart_GetStaticMethodClosure(library, cls, closure_name);
191  }
192  }
193  return closure;
194 }
195 
196 } // namespace flutter
DEF_SWITCHES_START snapshot asset path
Definition: switches.h:32
static const char * kCacheName
static Dart_Handle GetCallback(int64_t handle)
static const char * kClassNameKey
static const char * kRepresentationKey
static void SetCachePath(const std::string &path)
#define FML_LOG(severity)
Definition: logging.h:65
static int64_t GetCallbackHandle(const std::string &name, const std::string &class_name, const std::string &library_path)
static std::unique_ptr< DartCallbackRepresentation > GetCallbackInformation(int64_t handle)
std::function< void()> closure
Definition: closure.h:14
static const char * kLibraryPathKey
std::string JoinPaths(std::initializer_list< std::string > components)
Definition: paths.cc:14
static const char * kNameKey
static const char * kHandleKey
const char * name
Definition: fuchsia.cc:50
Dart_Handle ToDart(const T &object)