| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | |
| 5 #include "base/bind.h" | |
| 6 #include "base/message_loop/message_loop.h" | |
| 7 #include "base/run_loop.h" | |
| 8 #include "base/strings/string_split.h" | |
| 9 #include "base/synchronization/waitable_event.h" | |
| 10 #include "base/threading/platform_thread.h" | |
| 11 #include "base/trace_event/trace_event.h" | |
| 12 #include "mojo/application/application_runner_chromium.h" | 4 #include "mojo/application/application_runner_chromium.h" |
| 13 #include "mojo/application/content_handler_factory.h" | |
| 14 #include "mojo/common/tracing_impl.h" | |
| 15 #include "mojo/dart/embedder/dart_controller.h" | |
| 16 #include "mojo/public/c/system/main.h" | 5 #include "mojo/public/c/system/main.h" |
| 17 #include "mojo/public/cpp/application/application_delegate.h" | 6 #include "services/dart/content_handler_app.h" |
| 18 #include "mojo/public/cpp/application/application_impl.h" | |
| 19 #include "mojo/public/cpp/application/connect.h" | |
| 20 #include "mojo/public/cpp/bindings/binding.h" | |
| 21 #include "mojo/public/cpp/bindings/interface_request.h" | |
| 22 #include "mojo/services/tracing/interfaces/tracing.mojom.h" | |
| 23 #include "mojo/services/url_response_disk_cache/interfaces/url_response_disk_cac
he.mojom.h" | |
| 24 #include "services/dart/content_handler_app_service_connector.h" | |
| 25 #include "services/dart/dart_app.h" | |
| 26 #include "services/dart/dart_tracing.h" | |
| 27 #include "url/gurl.h" | |
| 28 | |
| 29 namespace dart { | |
| 30 | |
| 31 // Flags for the content handler: | |
| 32 const char kDartTimeline[] = "--dart-timeline"; | |
| 33 const char kDisableObservatory[] = "--disable-observatory"; | |
| 34 const char kEnableStrictMode[] = "--enable-strict-mode"; | |
| 35 const char kRunOnMessageLoop[] = "--run-on-message-loop"; | |
| 36 const char kTraceStartup[] = "--trace-startup"; | |
| 37 // Flags forwarded to the Dart VM: | |
| 38 const char kCompleteTimeline[] = "--complete-timeline"; | |
| 39 const char kPauseIsolatesOnStart[] = "--pause-isolates-on-start"; | |
| 40 const char kPauseIsolatesOnExit[] = "--pause-isolates-on-exit"; | |
| 41 | |
| 42 static bool IsDartZip(std::string url) { | |
| 43 // If the url doesn't end with ".dart" we assume it is a zipped up | |
| 44 // dart application. | |
| 45 return !base::EndsWith(url, ".dart", base::CompareCase::INSENSITIVE_ASCII); | |
| 46 } | |
| 47 | |
| 48 // Returns true if |requestedUrl| has a boolean query parameter named |param|. | |
| 49 static bool HasBoolQueryParam(const std::string& requestedUrl, | |
| 50 const std::string& param) { | |
| 51 std::string param_true = param + "=true"; | |
| 52 std::string param_false = param + "=false"; | |
| 53 | |
| 54 GURL url(requestedUrl); | |
| 55 if (url.has_query()) { | |
| 56 std::vector<std::string> query_parameters = base::SplitString( | |
| 57 url.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| 58 bool has_true = | |
| 59 std::find(query_parameters.begin(), | |
| 60 query_parameters.end(), | |
| 61 param_true) != query_parameters.end(); | |
| 62 bool has_false = | |
| 63 std::find(query_parameters.begin(), | |
| 64 query_parameters.end(), | |
| 65 param_false) != query_parameters.end(); | |
| 66 return has_true || has_false; | |
| 67 } | |
| 68 return false; | |
| 69 } | |
| 70 | |
| 71 // Returns the value of the boolean query parameter named |param|, or | |
| 72 // |default_value| if it |param| is not present. | |
| 73 static bool BoolQueryParamValue(const std::string& requestedUrl, | |
| 74 const std::string& param, | |
| 75 bool default_value) { | |
| 76 if (!HasBoolQueryParam(requestedUrl, param)) { | |
| 77 return default_value; | |
| 78 } | |
| 79 std::string param_true = param + "=true"; | |
| 80 std::string param_false = param + "=false"; | |
| 81 GURL url(requestedUrl); | |
| 82 DCHECK(url.has_query()); | |
| 83 std::vector<std::string> query_parameters = base::SplitString( | |
| 84 url.query(), "&", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| 85 bool has_true = | |
| 86 std::find(query_parameters.begin(), | |
| 87 query_parameters.end(), | |
| 88 param_true) != query_parameters.end(); | |
| 89 bool has_false = | |
| 90 std::find(query_parameters.begin(), | |
| 91 query_parameters.end(), | |
| 92 param_false) != query_parameters.end(); | |
| 93 if (has_true) { | |
| 94 return has_true; | |
| 95 } | |
| 96 if (has_false) { | |
| 97 return false; | |
| 98 } | |
| 99 return default_value; | |
| 100 } | |
| 101 | |
| 102 static bool HasStrictQueryParam(const std::string& requestedUrl) { | |
| 103 return BoolQueryParamValue(requestedUrl, "strict", false); | |
| 104 } | |
| 105 | |
| 106 class DartContentHandlerApp; | |
| 107 | |
| 108 class DartContentHandler : public mojo::ContentHandlerFactory::ManagedDelegate { | |
| 109 public: | |
| 110 DartContentHandler(DartContentHandlerApp* app, bool strict) | |
| 111 : app_(app), strict_(strict) { | |
| 112 } | |
| 113 | |
| 114 void set_handler_task_runner( | |
| 115 scoped_refptr<base::SingleThreadTaskRunner> handler_task_runner) { | |
| 116 handler_task_runner_ = handler_task_runner; | |
| 117 } | |
| 118 | |
| 119 private: | |
| 120 // Overridden from ContentHandlerFactory::ManagedDelegate: | |
| 121 scoped_ptr<mojo::ContentHandlerFactory::HandledApplicationHolder> | |
| 122 CreateApplication( | |
| 123 mojo::InterfaceRequest<mojo::Application> application_request, | |
| 124 mojo::URLResponsePtr response) override; | |
| 125 | |
| 126 DartContentHandlerApp* app_; | |
| 127 bool strict_; | |
| 128 scoped_refptr<base::SingleThreadTaskRunner> handler_task_runner_; | |
| 129 | |
| 130 DISALLOW_COPY_AND_ASSIGN(DartContentHandler); | |
| 131 }; | |
| 132 | |
| 133 class DartContentHandlerApp : public mojo::ApplicationDelegate { | |
| 134 public: | |
| 135 DartContentHandlerApp() | |
| 136 : content_handler_(this, false), | |
| 137 strict_content_handler_(this, true), | |
| 138 service_connector_(nullptr), | |
| 139 default_strict_(false), | |
| 140 run_on_message_loop_(false) {} | |
| 141 | |
| 142 ~DartContentHandlerApp() override { | |
| 143 // Shutdown the controller. | |
| 144 mojo::dart::DartController::Shutdown(); | |
| 145 delete service_connector_; | |
| 146 } | |
| 147 | |
| 148 void ExtractApplication(base::FilePath* application_dir, | |
| 149 mojo::URLResponsePtr response, | |
| 150 const base::Closure& callback) { | |
| 151 url_response_disk_cache_->UpdateAndGetExtracted( | |
| 152 response.Pass(), | |
| 153 [application_dir, callback](mojo::Array<uint8_t> application_dir_path, | |
| 154 mojo::Array<uint8_t> cache_path) { | |
| 155 if (application_dir_path.is_null()) { | |
| 156 *application_dir = base::FilePath(); | |
| 157 } else { | |
| 158 *application_dir = base::FilePath(std::string( | |
| 159 reinterpret_cast<char*>(&application_dir_path.front()), | |
| 160 application_dir_path.size())); | |
| 161 } | |
| 162 callback.Run(); | |
| 163 }); | |
| 164 } | |
| 165 | |
| 166 bool run_on_message_loop() const { | |
| 167 return run_on_message_loop_; | |
| 168 } | |
| 169 | |
| 170 private: | |
| 171 // Overridden from mojo::ApplicationDelegate: | |
| 172 void Initialize(mojo::ApplicationImpl* app) override { | |
| 173 // Tracing of content handler and controller. | |
| 174 tracing_.Initialize(app); | |
| 175 // Tracing of isolates and VM. | |
| 176 dart_tracing_.Initialize(app); | |
| 177 | |
| 178 // TODO(qsr): This has no effect for now, as the tracing infrastructure | |
| 179 // doesn't allow to trace anything before the tracing app connects to the | |
| 180 // application. | |
| 181 TRACE_EVENT0("dart_content_handler", "DartContentHandler::Initialize"); | |
| 182 | |
| 183 default_strict_ = app->HasArg(kEnableStrictMode); | |
| 184 content_handler_.set_handler_task_runner( | |
| 185 base::MessageLoop::current()->task_runner()); | |
| 186 strict_content_handler_.set_handler_task_runner( | |
| 187 base::MessageLoop::current()->task_runner()); | |
| 188 mojo::ConnectToService(app->shell(), "mojo:url_response_disk_cache", | |
| 189 GetProxy(&url_response_disk_cache_)); | |
| 190 service_connector_ = new ContentHandlerAppServiceConnector(app); | |
| 191 | |
| 192 if (app->HasArg(kRunOnMessageLoop)) { | |
| 193 run_on_message_loop_ = true; | |
| 194 } | |
| 195 | |
| 196 bool enable_observatory = true; | |
| 197 if (app->HasArg(kDisableObservatory)) { | |
| 198 enable_observatory = false; | |
| 199 } | |
| 200 | |
| 201 bool enable_dart_timeline = false; | |
| 202 if (app->HasArg(kDartTimeline)) { | |
| 203 enable_dart_timeline = true; | |
| 204 } | |
| 205 | |
| 206 std::vector<const char*> extra_args; | |
| 207 | |
| 208 if (app->HasArg(kPauseIsolatesOnStart)) { | |
| 209 extra_args.push_back(kPauseIsolatesOnStart); | |
| 210 } | |
| 211 | |
| 212 if (app->HasArg(kPauseIsolatesOnExit)) { | |
| 213 extra_args.push_back(kPauseIsolatesOnExit); | |
| 214 } | |
| 215 | |
| 216 if (app->HasArg(kCompleteTimeline)) { | |
| 217 extra_args.push_back(kCompleteTimeline); | |
| 218 } | |
| 219 | |
| 220 bool success = mojo::dart::DartController::Initialize( | |
| 221 service_connector_, | |
| 222 default_strict_, | |
| 223 enable_observatory, | |
| 224 enable_dart_timeline, | |
| 225 extra_args.data(), | |
| 226 extra_args.size()); | |
| 227 | |
| 228 if (app->HasArg(kTraceStartup)) { | |
| 229 DartTimelineController::EnableAll(); | |
| 230 } | |
| 231 if (!success) { | |
| 232 LOG(ERROR) << "Dart VM Initialization failed"; | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 // Overridden from ApplicationDelegate: | |
| 237 bool ConfigureIncomingConnection( | |
| 238 mojo::ServiceProviderImpl* service_provider_impl) override { | |
| 239 bool strict = HasStrictQueryParam( | |
| 240 service_provider_impl->connection_context().connection_url); | |
| 241 if (default_strict_ || strict) { | |
| 242 service_provider_impl->AddService<mojo::ContentHandler>( | |
| 243 mojo::ContentHandlerFactory::GetInterfaceRequestHandler( | |
| 244 &strict_content_handler_)); | |
| 245 } else { | |
| 246 service_provider_impl->AddService<mojo::ContentHandler>( | |
| 247 mojo::ContentHandlerFactory::GetInterfaceRequestHandler( | |
| 248 &content_handler_)); | |
| 249 } | |
| 250 return true; | |
| 251 } | |
| 252 | |
| 253 mojo::TracingImpl tracing_; | |
| 254 DartContentHandler content_handler_; | |
| 255 DartContentHandler strict_content_handler_; | |
| 256 mojo::URLResponseDiskCachePtr url_response_disk_cache_; | |
| 257 ContentHandlerAppServiceConnector* service_connector_; | |
| 258 DartTracingImpl dart_tracing_; | |
| 259 bool default_strict_; | |
| 260 bool run_on_message_loop_; | |
| 261 | |
| 262 DISALLOW_COPY_AND_ASSIGN(DartContentHandlerApp); | |
| 263 }; | |
| 264 | |
| 265 scoped_ptr<mojo::ContentHandlerFactory::HandledApplicationHolder> | |
| 266 DartContentHandler::CreateApplication( | |
| 267 mojo::InterfaceRequest<mojo::Application> application_request, | |
| 268 mojo::URLResponsePtr response) { | |
| 269 base::trace_event::TraceLog::GetInstance() | |
| 270 ->SetCurrentThreadBlocksMessageLoop(); | |
| 271 | |
| 272 TRACE_EVENT1("dart_content_handler", "DartContentHandler::CreateApplication", | |
| 273 "url", response->url.get()); | |
| 274 | |
| 275 const bool run_on_message_loop = app_->run_on_message_loop(); | |
| 276 base::FilePath application_dir; | |
| 277 std::string url = response->url.get(); | |
| 278 const char* kPauseIsolatesOnStart = "pauseIsolatesOnStart"; | |
| 279 const char* kPauseIsolatesOnExit = "pauseIsolatesOnExit"; | |
| 280 const bool override_pause_isolates_flags = | |
| 281 HasBoolQueryParam(url, kPauseIsolatesOnStart) || | |
| 282 HasBoolQueryParam(url, kPauseIsolatesOnExit); | |
| 283 const bool pause_isolates_on_start = BoolQueryParamValue( | |
| 284 url, | |
| 285 kPauseIsolatesOnStart, | |
| 286 mojo::dart::DartControllerConfig::kDefaultPauseOnStart); | |
| 287 const bool pause_isolates_on_exit = BoolQueryParamValue( | |
| 288 url, | |
| 289 kPauseIsolatesOnExit, | |
| 290 mojo::dart::DartControllerConfig::kDefaultPauseOnExit); | |
| 291 if (IsDartZip(response->url.get())) { | |
| 292 // Loading a zipped snapshot: | |
| 293 // 1) Extract the zip file. | |
| 294 // 2) Launch from temporary directory (|application_dir|). | |
| 295 handler_task_runner_->PostTask( | |
| 296 FROM_HERE, | |
| 297 base::Bind( | |
| 298 &DartContentHandlerApp::ExtractApplication, base::Unretained(app_), | |
| 299 base::Unretained(&application_dir), base::Passed(response.Pass()), | |
| 300 base::Bind( | |
| 301 base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask), | |
| 302 base::MessageLoop::current()->task_runner(), FROM_HERE, | |
| 303 base::MessageLoop::QuitWhenIdleClosure()))); | |
| 304 base::RunLoop().Run(); | |
| 305 return make_scoped_ptr( | |
| 306 new DartApp(application_request.Pass(), | |
| 307 url, | |
| 308 application_dir, | |
| 309 strict_, | |
| 310 run_on_message_loop, | |
| 311 override_pause_isolates_flags, | |
| 312 pause_isolates_on_start, | |
| 313 pause_isolates_on_exit)); | |
| 314 } else { | |
| 315 // Loading a raw .dart file pointed at by |url|. | |
| 316 return make_scoped_ptr( | |
| 317 new DartApp(application_request.Pass(), | |
| 318 url, | |
| 319 strict_, | |
| 320 run_on_message_loop, | |
| 321 override_pause_isolates_flags, | |
| 322 pause_isolates_on_start, | |
| 323 pause_isolates_on_exit)); | |
| 324 } | |
| 325 } | |
| 326 | |
| 327 } // namespace dart | |
| 328 | 7 |
| 329 MojoResult MojoMain(MojoHandle application_request) { | 8 MojoResult MojoMain(MojoHandle application_request) { |
| 330 mojo::ApplicationRunnerChromium runner(new dart::DartContentHandlerApp); | 9 mojo::ApplicationRunnerChromium runner(new dart::DartContentHandlerApp); |
| 331 return runner.Run(application_request); | 10 return runner.Run(application_request); |
| 332 } | 11 } |
| OLD | NEW |