| // Copyright 2014 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #include "services/dart/dart_app.h" | 
 |  | 
 | #include "base/bind.h" | 
 | #include "base/files/file_path.h" | 
 | #include "base/files/file_util.h" | 
 | #include "base/logging.h" | 
 | #include "base/message_loop/message_loop.h" | 
 | #include "base/path_service.h" | 
 | #include "base/trace_event/trace_event.h" | 
 | #include "mojo/dart/embedder/dart_controller.h" | 
 | #include "mojo/dart/embedder/mojo_dart_state.h" | 
 | #include "mojo/data_pipe_utils/data_pipe_utils.h" | 
 | #include "mojo/public/cpp/bindings/interface_request.h" | 
 | #include "third_party/zlib/google/zip_reader.h" | 
 | #include "url/gurl.h" | 
 |  | 
 | using mojo::Application; | 
 |  | 
 | namespace dart { | 
 |  | 
 | DartApp::DartApp(mojo::InterfaceRequest<Application> application_request, | 
 |                  const std::string& base_uri, | 
 |                  const base::FilePath& application_dir, | 
 |                  bool strict, | 
 |                  bool run_on_message_loop, | 
 |                  bool override_pause_isolates_flags, | 
 |                  bool pause_isolates_on_start, | 
 |                  bool pause_isolates_on_exit) | 
 |     : application_request_(application_request.Pass()), | 
 |       application_dir_(application_dir), | 
 |       main_isolate_(nullptr) { | 
 |   base::FilePath snapshot_path = application_dir_.Append("snapshot_blob.bin"); | 
 |   config_.base_uri = base_uri; | 
 |   config_.use_dart_run_loop = !run_on_message_loop; | 
 |   // Look for snapshot_blob.bin. If exists, then load from snapshot. | 
 |   if (base::PathExists(snapshot_path)) { | 
 |     config_.script_uri = snapshot_path.AsUTF8Unsafe(); | 
 |     config_.package_root = ""; | 
 |   } else { | 
 |     LOG(ERROR) << "Dart entry point could not be found under: " | 
 |                << application_dir_.AsUTF8Unsafe(); | 
 |     base::MessageLoop::current()->QuitWhenIdle(); | 
 |   } | 
 |  | 
 |   config_.application_data = reinterpret_cast<void*>(this); | 
 |   config_.strict_compilation = strict; | 
 |   config_.SetVmFlags(nullptr, 0); | 
 |   if (override_pause_isolates_flags) { | 
 |     config_.OverridePauseIsolateFlags(pause_isolates_on_start, | 
 |                                       pause_isolates_on_exit); | 
 |   } | 
 |  | 
 |   base::MessageLoop::current()->PostTask(FROM_HERE, | 
 |       base::Bind(&DartApp::OnAppLoaded, base::Unretained(this))); | 
 | } | 
 |  | 
 | // Assume that |url| ends in a file name in lib/, and as a peer to lib/ | 
 | // is the packages directory. | 
 | // 1) Strip the filename. | 
 | // 2) Strip lib/ | 
 | // 3) Append with packages/. | 
 | // 4) Reconstruct full url. | 
 | static std::string SimplePackageRootFromUrl(std::string url) { | 
 |   GURL gurl = GURL(url); | 
 |   base::FilePath path = base::FilePath(gurl.path()); | 
 |   path = path.DirName(); | 
 |   path = path.DirName(); | 
 |   path = path.Append("packages"); | 
 |   path = path.AsEndingWithSeparator(); | 
 |   const std::string& path_string = path.value(); | 
 |   GURL::Replacements path_replacement; | 
 |   path_replacement.SetPath(path_string.data(), | 
 |                            url::Component(0, path_string.size())); | 
 |   gurl = gurl.ReplaceComponents(path_replacement); | 
 |   return gurl.spec(); | 
 | } | 
 |  | 
 | // Returns the path component from |url|. | 
 | static std::string ExtractPath(std::string url) { | 
 |   GURL gurl = GURL(url); | 
 |   return gurl.path(); | 
 | } | 
 |  | 
 | static bool IsFileScheme(std::string url) { | 
 |   GURL gurl = GURL(url); | 
 |   return gurl.SchemeIsFile(); | 
 | } | 
 |  | 
 | DartApp::DartApp(mojo::InterfaceRequest<Application> application_request, | 
 |                  const std::string& url, | 
 |                  bool strict, | 
 |                  bool run_on_message_loop, | 
 |                  bool override_pause_isolates_flags, | 
 |                  bool pause_isolates_on_start, | 
 |                  bool pause_isolates_on_exit) | 
 |     : application_request_(application_request.Pass()), | 
 |       main_isolate_(nullptr) { | 
 |   config_.application_data = reinterpret_cast<void*>(this); | 
 |   config_.strict_compilation = strict; | 
 |   config_.base_uri = url; | 
 |   config_.use_dart_run_loop = !run_on_message_loop; | 
 |   if (IsFileScheme(url)) { | 
 |     // Strip file:// and use the path directly. | 
 |     config_.script_uri = ExtractPath(url); | 
 |     config_.package_root = ExtractPath(SimplePackageRootFromUrl(url)); | 
 |     config_.use_network_loader = false; | 
 |   } else { | 
 |     // Use the full url. | 
 |     config_.script_uri = url; | 
 |     config_.package_root = SimplePackageRootFromUrl(url); | 
 |     config_.use_network_loader = true; | 
 |   } | 
 |   config_.SetVmFlags(nullptr, 0); | 
 |   if (override_pause_isolates_flags) { | 
 |     config_.OverridePauseIsolateFlags(pause_isolates_on_start, | 
 |                                       pause_isolates_on_exit); | 
 |   } | 
 |  | 
 |   base::MessageLoop::current()->PostTask(FROM_HERE, | 
 |       base::Bind(&DartApp::OnAppLoaded, base::Unretained(this))); | 
 | } | 
 |  | 
 | DartApp::~DartApp() { | 
 |   if (main_isolate_ != nullptr) { | 
 |     mojo::dart::DartController::ShutdownIsolate(main_isolate_); | 
 |     main_isolate_ = nullptr; | 
 |   } | 
 | } | 
 |  | 
 | void DartApp::OnAppLoaded() { | 
 |   char* error = nullptr; | 
 |   config_.handle = application_request_.PassMessagePipe().release().value(); | 
 |   config_.error = &error; | 
 |   main_isolate_ = mojo::dart::DartController::StartupIsolate(config_); | 
 |   if (!main_isolate_) { | 
 |     LOG(ERROR) << error; | 
 |     free(error); | 
 |   } | 
 |   if (config_.use_dart_run_loop) { | 
 |     // let TraceLog know about that RunToCompletion blocks the message loop. | 
 |     auto trace_log = base::trace_event::TraceLog::GetInstance(); | 
 |     trace_log->SetCurrentThreadBlocksMessageLoop(); | 
 |     mojo::dart::DartController::RunToCompletion(main_isolate_); | 
 |     base::MessageLoop::current()->QuitWhenIdle(); | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace dart |