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