Flutter Engine
service_protocol.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 #define RAPIDJSON_HAS_STDSTRING 1
6 
7 #include "flutter/runtime/service_protocol.h"
8 
9 #include <cstring>
10 #include <sstream>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include "flutter/fml/posix_wrappers.h"
16 #include "flutter/fml/synchronization/waitable_event.h"
17 #include "rapidjson/stringbuffer.h"
18 #include "rapidjson/writer.h"
19 #include "third_party/dart/runtime/include/dart_tools_api.h"
20 
21 namespace flutter {
22 
23 const std::string_view ServiceProtocol::kScreenshotExtensionName =
24  "_flutter.screenshot";
25 const std::string_view ServiceProtocol::kScreenshotSkpExtensionName =
26  "_flutter.screenshotSkp";
27 const std::string_view ServiceProtocol::kRunInViewExtensionName =
28  "_flutter.runInView";
30  "_flutter.flushUIThreadTasks";
32  "_flutter.setAssetBundlePath";
34  "_flutter.getDisplayRefreshRate";
35 const std::string_view ServiceProtocol::kGetSkSLsExtensionName =
36  "_flutter.getSkSLs";
37 const std::string_view
39  "_flutter.estimateRasterCacheMemory";
40 
41 static constexpr std::string_view kViewIdPrefx = "_flutterView/";
42 static constexpr std::string_view kListViewsExtensionName =
43  "_flutter.listViews";
44 
46  : endpoints_({
47  // Private
49 
50  // Public
59  }),
60  handlers_mutex_(fml::SharedMutex::Create()) {}
61 
63  ToggleHooks(false);
64 }
65 
67  Handler::Description description) {
68  fml::UniqueLock lock(*handlers_mutex_);
69  handlers_.emplace(handler, description);
70 }
71 
73  fml::UniqueLock lock(*handlers_mutex_);
74  handlers_.erase(handler);
75 }
76 
78  Handler::Description description) {
79  fml::SharedLock lock(*handlers_mutex_);
80  auto it = handlers_.find(handler);
81  if (it != handlers_.end()) {
82  it->second.Store(description);
83  }
84 }
85 
87  for (const auto& endpoint : endpoints_) {
88  Dart_RegisterIsolateServiceRequestCallback(
89  endpoint.data(), // method
90  &ServiceProtocol::HandleMessage, // callback
91  set ? this : nullptr // user data
92  );
93  }
94 }
95 
96 static void WriteServerErrorResponse(rapidjson::Document* document,
97  const char* message) {
98  document->SetObject();
99  document->AddMember("code", -32000, document->GetAllocator());
100  rapidjson::Value message_value;
101  message_value.SetString(message, document->GetAllocator());
102  document->AddMember("message", message_value, document->GetAllocator());
103 }
104 
105 bool ServiceProtocol::HandleMessage(const char* method,
106  const char** param_keys,
107  const char** param_values,
108  intptr_t num_params,
109  void* user_data,
110  const char** json_object) {
112  for (intptr_t i = 0; i < num_params; i++) {
113  params[std::string_view{param_keys[i]}] = std::string_view{param_values[i]};
114  }
115 
116 #ifndef NDEBUG
117  FML_DLOG(INFO) << "Service protcol method: " << method;
118  FML_DLOG(INFO) << "Arguments: " << params.size();
119  for (intptr_t i = 0; i < num_params; i++) {
120  FML_DLOG(INFO) << " " << i + 1 << ": " << param_keys[i] << " = "
121  << param_values[i];
122  }
123 #endif // NDEBUG
124 
125  rapidjson::Document document;
126  bool result = HandleMessage(std::string_view{method}, //
127  params, //
128  static_cast<ServiceProtocol*>(user_data), //
129  &document //
130  );
131  rapidjson::StringBuffer buffer;
132  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
133  document.Accept(writer);
134  *json_object = fml::strdup(buffer.GetString());
135 
136 #ifndef NDEBUG
137  FML_DLOG(INFO) << "Response: " << *json_object;
138  FML_DLOG(INFO) << "RPC Result: " << result;
139 #endif // NDEBUG
140 
141  return result;
142 }
143 
144 bool ServiceProtocol::HandleMessage(std::string_view method,
145  const Handler::ServiceProtocolMap& params,
146  ServiceProtocol* service_protocol,
147  rapidjson::Document* response) {
148  if (service_protocol == nullptr) {
149  WriteServerErrorResponse(response, "Service protocol unavailable.");
150  return false;
151  }
152 
153  return service_protocol->HandleMessage(method, params, response);
154 }
155 
156 [[nodiscard]] static bool HandleMessageOnHandler(
157  ServiceProtocol::Handler* handler,
158  std::string_view method,
160  rapidjson::Document* document) {
161  FML_DCHECK(handler);
163  bool result = false;
165  handler->GetServiceProtocolHandlerTaskRunner(method),
166  [&latch, //
167  &result, //
168  &handler, //
169  &method, //
170  &params, //
171  &document //
172  ]() {
173  result =
174  handler->HandleServiceProtocolMessage(method, params, document);
175  latch.Signal();
176  });
177  latch.Wait();
178  return result;
179 }
180 
181 bool ServiceProtocol::HandleMessage(std::string_view method,
182  const Handler::ServiceProtocolMap& params,
183  rapidjson::Document* response) const {
184  if (method == kListViewsExtensionName) {
185  // So far, this is the only built-in method that does not forward to the
186  // dynamic set of handlers.
187  return HandleListViewsMethod(response);
188  }
189 
190  fml::SharedLock lock(*handlers_mutex_);
191 
192  if (handlers_.size() == 0) {
193  WriteServerErrorResponse(response,
194  "There are no running service protocol handlers.");
195  return false;
196  }
197 
198  // Find the handler by its "viewId" in the params.
199  auto view_id_param_found = params.find(std::string_view{"viewId"});
200  if (view_id_param_found != params.end()) {
201  auto* handler = reinterpret_cast<Handler*>(std::stoull(
202  view_id_param_found->second.data() + kViewIdPrefx.size(), nullptr, 16));
203  auto handler_found = handlers_.find(handler);
204  if (handler_found != handlers_.end()) {
205  return HandleMessageOnHandler(handler, method, params, response);
206  }
207  }
208 
209  // Handle legacy calls that do not specify a handler in their args.
210  // TODO(chinmaygarde): Deprecate these calls in the tools and remove these
211  // fallbacks.
212  if (method == kScreenshotExtensionName ||
213  method == kScreenshotSkpExtensionName ||
215  return HandleMessageOnHandler(handlers_.begin()->first, method, params,
216  response);
217  }
218 
220  response,
221  "Service protocol could not handle or find a handler for the "
222  "requested method.");
223  return false;
224 }
225 
226 static std::string CreateFlutterViewID(intptr_t handler) {
227  std::stringstream stream;
228  stream << kViewIdPrefx << "0x" << std::hex << handler;
229  return stream.str();
230 }
231 
232 static std::string CreateIsolateID(int64_t isolate) {
233  std::stringstream stream;
234  stream << "isolates/" << isolate;
235  return stream.str();
236 }
237 
239  Handler* handler,
240  rapidjson::Value& view,
241  rapidjson::MemoryPoolAllocator<>& allocator) const {
242  view.SetObject();
243  view.AddMember("type", "FlutterView", allocator);
244  view.AddMember("id", CreateFlutterViewID(reinterpret_cast<intptr_t>(handler)),
245  allocator);
246  if (isolate_port != 0) {
247  rapidjson::Value isolate(rapidjson::Type::kObjectType);
248  {
249  isolate.AddMember("type", "@Isolate", allocator);
250  isolate.AddMember("fixedId", true, allocator);
251  isolate.AddMember("id", CreateIsolateID(isolate_port), allocator);
252  isolate.AddMember("name", isolate_name, allocator);
253  isolate.AddMember("number", isolate_port, allocator);
254  }
255  view.AddMember("isolate", isolate, allocator);
256  }
257 }
258 
259 bool ServiceProtocol::HandleListViewsMethod(
260  rapidjson::Document* response) const {
261  fml::SharedLock lock(*handlers_mutex_);
262  std::vector<std::pair<intptr_t, Handler::Description>> descriptions;
263  for (const auto& handler : handlers_) {
264  descriptions.emplace_back(reinterpret_cast<intptr_t>(handler.first),
265  handler.second.Load());
266  }
267 
268  auto& allocator = response->GetAllocator();
269 
270  // Construct the response objects.
271  response->SetObject();
272  response->AddMember("type", "FlutterViewList", allocator);
273 
274  rapidjson::Value viewsList(rapidjson::Type::kArrayType);
275  for (const auto& description : descriptions) {
276  rapidjson::Value view(rapidjson::Type::kObjectType);
277  description.second.Write(reinterpret_cast<Handler*>(description.first),
278  view, allocator);
279  viewsList.PushBack(view, allocator);
280  }
281 
282  response->AddMember("views", viewsList, allocator);
283 
284  return true;
285 }
286 
287 } // namespace flutter
static const std::string_view kGetDisplayRefreshRateExtensionName
std::map< std::string_view, std::string_view > ServiceProtocolMap
static const std::string_view kRunInViewExtensionName
#define FML_DCHECK(condition)
Definition: logging.h:86
static constexpr std::string_view kListViewsExtensionName
static void RunNowOrPostTask(fml::RefPtr< fml::TaskRunner > runner, const fml::closure &task)
Definition: task_runner.cc:55
static std::string CreateIsolateID(int64_t isolate)
void SetHandlerDescription(Handler *handler, Handler::Description description)
static const std::string_view kScreenshotExtensionName
static const std::string_view kFlushUIThreadTasksExtensionName
void Write(Handler *handler, rapidjson::Value &value, rapidjson::MemoryPoolAllocator<> &allocator) const
G_BEGIN_DECLS FlValue gpointer user_data
void AddHandler(Handler *handler, Handler::Description description)
static SharedMutex * Create()
static constexpr std::string_view kViewIdPrefx
virtual fml::RefPtr< fml::TaskRunner > GetServiceProtocolHandlerTaskRunner(std::string_view method) const =0
static std::string CreateFlutterViewID(intptr_t handler)
static bool HandleMessageOnHandler(ServiceProtocol::Handler *handler, std::string_view method, const ServiceProtocol::Handler::ServiceProtocolMap &params, rapidjson::Document *document)
#define FML_DLOG(severity)
Definition: logging.h:85
static void WriteServerErrorResponse(rapidjson::Document *document, const char *message)
char * strdup(const char *str1)
void RemoveHandler(Handler *handler)
static const std::string_view kScreenshotSkpExtensionName
static const std::string_view kSetAssetBundlePathExtensionName
static const std::string_view kGetSkSLsExtensionName
static const std::string_view kEstimateRasterCacheMemoryExtensionName