11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/apps/js/js_app.h"
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "gin/array_buffer.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "gin/converter.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/apps/js/application_delegate_impl.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/apps/js/mojo_module.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "mojo/common/data_pipe_utils.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace mojo {
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace apps {
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciJSApp::JSApp(ApplicationDelegateImpl* content_handler_app,
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             const std::string& url,
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             URLResponsePtr content)
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : content_handler_app_(content_handler_app),
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      url_(url),
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content_(content.Pass()),
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      thread_("Mojo JS " + url),
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content_handler_task_runner_(
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          base::MessageLoop::current()->task_runner()) {
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(on_content_handler_thread());
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  runner_delegate_.AddBuiltinModule(Mojo::kModuleName,
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                    base::Bind(Mojo::GetModule, this));
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciJSApp::~JSApp() {
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool JSApp::Start() {
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(!js_app_task_runner_.get() && on_content_handler_thread());
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::Thread::Options thread_options(base::MessageLoop::TYPE_IO, 0);
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  thread_.StartWithOptions(thread_options);
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(hansmuller): check thread_.StartWithOptions() return value.
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(hansmuller): need to funnel Run() failures back to the caller.
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  thread_.message_loop()->PostTask(
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE, base::Bind(&JSApp::Run, base::Unretained(this)));
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return true;
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid JSApp::Quit() {
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(on_js_app_thread());
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The terminate operation is posted to the message_loop so that
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // the shell_runner isn't destroyed before this JS function returns.
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  thread_.message_loop()->PostTask(
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE, base::Bind(&JSApp::Terminate, base::Unretained(this)));
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciHandle JSApp::ConnectToService(const std::string& application_url,
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               const std::string& interface_name) {
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(on_js_app_thread());
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MessagePipe pipe;
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  content_handler_task_runner_->PostTask(
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ApplicationDelegateImpl::ConnectToService,
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(content_handler_app_),
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Passed(pipe.handle1.Pass()),
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 application_url,
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 interface_name));
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return pipe.handle0.release();
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid JSApp::Run() {
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CHECK(!js_app_task_runner_.get() && !on_content_handler_thread());
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  js_app_task_runner_ = base::MessageLoop::current()->task_runner();
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(hansmuller): check the return value and fail gracefully.
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string module;
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  common::BlockingCopyToString(content_->body.Pass(), &module);
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gin::IsolateHolder::Initialize(gin::IsolateHolder::kStrictMode,
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                 gin::ArrayBufferAllocator::SharedInstance());
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  isolate_holder_.reset(new gin::IsolateHolder());
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  isolate_holder_->AddRunMicrotasksObserver();
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  shell_runner_.reset(
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      new gin::ShellRunner(&runner_delegate_, isolate_holder_->isolate()));
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(hansmuller): exiting this scope here is OK?
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  gin::Runner::Scope scope(shell_runner_.get());
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  shell_runner_->Run(module.c_str(), url_.c_str());
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid JSApp::Terminate() {
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  isolate_holder_->RemoveRunMicrotasksObserver();
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  shell_runner_.reset(NULL);
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // This JSApp's thread must be stopped on the thread that started it. Ask the
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // content_handler_app_ to erase its AppVector entry for this app, which
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // implicitly destroys this JSApp and stops its thread.
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  content_handler_task_runner_->PostTask(
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      FROM_HERE,
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ApplicationDelegateImpl::QuitJSApp,
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(content_handler_app_),
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 base::Unretained(this)));
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool JSApp::on_content_handler_thread() const {
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return content_handler_task_runner_.get() &&
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         content_handler_task_runner_.get() ==
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             base::MessageLoop::current()->task_runner().get();
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool JSApp::on_js_app_thread() const {
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return js_app_task_runner_.get() &&
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci         js_app_task_runner_.get() ==
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci             base::MessageLoop::current()->task_runner().get();
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace apps
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace mojo
121