js_app.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
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
14namespace mojo {
15namespace apps {
16
17JSApp::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
31JSApp::~JSApp() {
32}
33
34bool 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
47void 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
56Handle 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
72void 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
93void 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
107bool 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
113bool 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