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