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