Home | History | Annotate | Download | only in js
      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
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/apps/js/js_app.h"
      6 
      7 #include "base/bind.h"
      8 #include "gin/array_buffer.h"
      9 #include "gin/converter.h"
     10 #include "mojo/apps/js/application_delegate_impl.h"
     11 #include "mojo/apps/js/mojo_module.h"
     12 #include "mojo/common/data_pipe_utils.h"
     13 
     14 namespace mojo {
     15 namespace apps {
     16 
     17 JSApp::JSApp(ApplicationDelegateImpl* content_handler_app,
     18              const std::string& url,
     19              URLResponsePtr content)
     20     : content_handler_app_(content_handler_app),
     21       url_(url),
     22       content_(content.Pass()),
     23       thread_("Mojo JS " + url),
     24       content_handler_task_runner_(
     25           base::MessageLoop::current()->task_runner()) {
     26   CHECK(on_content_handler_thread());
     27   runner_delegate_.AddBuiltinModule(Mojo::kModuleName,
     28                                     base::Bind(Mojo::GetModule, this));
     29 }
     30 
     31 JSApp::~JSApp() {
     32 }
     33 
     34 bool JSApp::Start() {
     35   CHECK(!js_app_task_runner_.get() && on_content_handler_thread());
     36   base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
     37   thread_.StartWithOptions(thread_options);
     38 
     39   // TODO(hansmuller): check thread_.StartWithOptions() return value.
     40   // TODO(hansmuller): need to funnel Run() failures back to the caller.
     41 
     42   thread_.message_loop()->PostTask(
     43       FROM_HERE, base::Bind(&JSApp::Run, base::Unretained(this)));
     44   return true;
     45 }
     46 
     47 void JSApp::Quit() {
     48   CHECK(on_js_app_thread());
     49 
     50   // The terminate operation is posted to the message_loop so that
     51   // the shell_runner isn't destroyed before this JS function returns.
     52   thread_.message_loop()->PostTask(
     53       FROM_HERE, base::Bind(&JSApp::Terminate, base::Unretained(this)));
     54 }
     55 
     56 Handle JSApp::ConnectToService(const std::string& application_url,
     57                                const std::string& interface_name) {
     58   CHECK(on_js_app_thread());
     59   MessagePipe pipe;
     60 
     61   content_handler_task_runner_->PostTask(
     62       FROM_HERE,
     63       base::Bind(&ApplicationDelegateImpl::ConnectToService,
     64                  base::Unretained(content_handler_app_),
     65                  base::Passed(pipe.handle1.Pass()),
     66                  application_url,
     67                  interface_name));
     68 
     69   return pipe.handle0.release();
     70 }
     71 
     72 void JSApp::Run() {
     73   CHECK(!js_app_task_runner_.get() && !on_content_handler_thread());
     74   js_app_task_runner_ = base::MessageLoop::current()->task_runner();
     75 
     76   // TODO(hansmuller): check the return value and fail gracefully.
     77   std::string module;
     78   common::BlockingCopyToString(content_->body.Pass(), &module);
     79 
     80   gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
     81                                  gin::ArrayBufferAllocator::SharedInstance());
     82   isolate_holder_.reset(new gin::IsolateHolder());
     83   isolate_holder_->AddRunMicrotasksObserver();
     84 
     85   shell_runner_.reset(
     86       new gin::ShellRunner(&runner_delegate_, isolate_holder_->isolate()));
     87 
     88   // TODO(hansmuller): exiting this scope here is OK?
     89   gin::Runner::Scope scope(shell_runner_.get());
     90   shell_runner_->Run(module.c_str(), url_.c_str());
     91 }
     92 
     93 void JSApp::Terminate() {
     94   isolate_holder_->RemoveRunMicrotasksObserver();
     95   shell_runner_.reset(NULL);
     96 
     97   // This JSApp's thread must be stopped on the thread that started it. Ask the
     98   // content_handler_app_ to erase its AppVector entry for this app, which
     99   // implicitly destroys this JSApp and stops its thread.
    100   content_handler_task_runner_->PostTask(
    101       FROM_HERE,
    102       base::Bind(&ApplicationDelegateImpl::QuitJSApp,
    103                  base::Unretained(content_handler_app_),
    104                  base::Unretained(this)));
    105 }
    106 
    107 bool JSApp::on_content_handler_thread() const {
    108   return content_handler_task_runner_.get() &&
    109          content_handler_task_runner_.get() ==
    110              base::MessageLoop::current()->task_runner().get();
    111 }
    112 
    113 bool JSApp::on_js_app_thread() const {
    114   return js_app_task_runner_.get() &&
    115          js_app_task_runner_.get() ==
    116              base::MessageLoop::current()->task_runner().get();
    117 }
    118 
    119 }  // namespace apps
    120 }  // namespace mojo
    121