diff options
Diffstat (limited to 'extensions/renderer')
-rw-r--r-- | extensions/renderer/dispatcher.cc | 6 | ||||
-rw-r--r-- | extensions/renderer/resources/test_custom_bindings.js | 5 | ||||
-rw-r--r-- | extensions/renderer/test_native_handler.cc | 24 | ||||
-rw-r--r-- | extensions/renderer/test_native_handler.h | 28 | ||||
-rw-r--r-- | extensions/renderer/wake_event_page.cc | 173 | ||||
-rw-r--r-- | extensions/renderer/wake_event_page.h | 108 |
6 files changed, 344 insertions, 0 deletions
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc index ed64dfd..636a2bf 100644 --- a/extensions/renderer/dispatcher.cc +++ b/extensions/renderer/dispatcher.cc @@ -81,10 +81,12 @@ #include "extensions/renderer/send_request_natives.h" #include "extensions/renderer/set_icon_natives.h" #include "extensions/renderer/test_features_native_handler.h" +#include "extensions/renderer/test_native_handler.h" #include "extensions/renderer/user_gestures_native_handler.h" #include "extensions/renderer/utils_native_handler.h" #include "extensions/renderer/v8_context_native_handler.h" #include "extensions/renderer/v8_helpers.h" +#include "extensions/renderer/wake_event_page.h" #include "grit/extensions_renderer_resources.h" #include "third_party/WebKit/public/platform/WebString.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" @@ -210,6 +212,7 @@ Dispatcher::Dispatcher(DispatcherDelegate* delegate) user_script_set_manager_observer_.Add(user_script_set_manager_.get()); request_sender_.reset(new RequestSender(this)); PopulateSourceMap(); + WakeEventPage::Get()->Init(content::RenderThread::Get()); // chrome-extensions: and chrome-extensions-resource: schemes should be // treated as secure because communication with them is entirely in the @@ -668,6 +671,9 @@ void Dispatcher::RegisterNativeHandlers(ModuleSystem* module_system, "test_features", scoped_ptr<NativeHandler>(new TestFeaturesNativeHandler(context))); module_system->RegisterNativeHandler( + "test_native_handler", + scoped_ptr<NativeHandler>(new TestNativeHandler(context))); + module_system->RegisterNativeHandler( "user_gestures", scoped_ptr<NativeHandler>(new UserGesturesNativeHandler(context))); module_system->RegisterNativeHandler( diff --git a/extensions/renderer/resources/test_custom_bindings.js b/extensions/renderer/resources/test_custom_bindings.js index ebb3f1b..7310f06 100644 --- a/extensions/renderer/resources/test_custom_bindings.js +++ b/extensions/renderer/resources/test_custom_bindings.js @@ -11,6 +11,7 @@ var environmentSpecificBindings = require('test_environment_specific_bindings'); var GetExtensionAPIDefinitionsForTest = requireNative('apiDefinitions').GetExtensionAPIDefinitionsForTest; var GetAPIFeatures = requireNative('test_features').GetAPIFeatures; +var natives = requireNative('test_native_handler'); var uncaughtExceptionHandler = require('uncaught_exception_handler'); var userGestures = requireNative('user_gestures'); @@ -353,6 +354,10 @@ binding.registerCustomHook(function(api) { uncaughtExceptionHandler.setHandler(callback); }); + apiFunctions.setHandleRequest('getWakeEventPage', function() { + return natives.GetWakeEventPage(); + }); + environmentSpecificBindings.registerHooks(api); }); diff --git a/extensions/renderer/test_native_handler.cc b/extensions/renderer/test_native_handler.cc new file mode 100644 index 0000000..31e7dcb --- /dev/null +++ b/extensions/renderer/test_native_handler.cc @@ -0,0 +1,24 @@ +// Copyright 2015 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 "extensions/renderer/test_native_handler.h" + +#include "extensions/renderer/wake_event_page.h" + +namespace extensions { + +TestNativeHandler::TestNativeHandler(ScriptContext* context) + : ObjectBackedNativeHandler(context) { + RouteFunction( + "GetWakeEventPage", + base::Bind(&TestNativeHandler::GetWakeEventPage, base::Unretained(this))); +} + +void TestNativeHandler::GetWakeEventPage( + const v8::FunctionCallbackInfo<v8::Value>& args) { + CHECK_EQ(0, args.Length()); + args.GetReturnValue().Set(WakeEventPage::Get()->GetForContext(context())); +} + +} // namespace extensions diff --git a/extensions/renderer/test_native_handler.h b/extensions/renderer/test_native_handler.h new file mode 100644 index 0000000..057329d --- /dev/null +++ b/extensions/renderer/test_native_handler.h @@ -0,0 +1,28 @@ +// Copyright 2015 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. + +#ifndef EXTENSIONS_RENDERER_TEST_NATIVE_HANDLER_H_ +#define EXTENSIONS_RENDERER_TEST_NATIVE_HANDLER_H_ + +#include "base/compiler_specific.h" +#include "extensions/renderer/object_backed_native_handler.h" +#include "v8/include/v8.h" + +namespace extensions { +class ScriptContext; + +// NativeHandler for the chrome.test API. +class TestNativeHandler : public ObjectBackedNativeHandler { + public: + explicit TestNativeHandler(ScriptContext* context); + + private: + void GetWakeEventPage(const v8::FunctionCallbackInfo<v8::Value>& args); + + DISALLOW_COPY_AND_ASSIGN(TestNativeHandler); +}; + +} // namespace extensions + +#endif // EXTENSIONS_RENDERER_TEST_NATIVE_HANDLER_H_ diff --git a/extensions/renderer/wake_event_page.cc b/extensions/renderer/wake_event_page.cc new file mode 100644 index 0000000..1bc4304 --- /dev/null +++ b/extensions/renderer/wake_event_page.cc @@ -0,0 +1,173 @@ +// Copyright 2015 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 "extensions/renderer/wake_event_page.h" + +#include "base/atomic_sequence_num.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/renderer/render_thread.h" +#include "extensions/common/extension_messages.h" +#include "extensions/renderer/object_backed_native_handler.h" +#include "extensions/renderer/script_context.h" +#include "extensions/renderer/v8_helpers.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_macros.h" + +namespace extensions { + +using namespace v8_helpers; + +namespace { + +base::LazyInstance<WakeEventPage> g_instance = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +class WakeEventPage::WakeEventPageNativeHandler + : public ObjectBackedNativeHandler { + public: + // Handles own lifetime. + WakeEventPageNativeHandler(ScriptContext* context, + const std::string& name, + const MakeRequestCallback& make_request) + : ObjectBackedNativeHandler(context), + make_request_(make_request), + weak_ptr_factory_(this) { + // Use Unretained not a WeakPtr because RouteFunction is tied to the + // lifetime of this, so there is no way for DoWakeEventPage to be called + // after destruction. + RouteFunction(name, base::Bind(&WakeEventPageNativeHandler::DoWakeEventPage, + base::Unretained(this))); + // Delete self on invalidation. base::Unretained because by definition this + // can't be deleted before it's deleted. + context->AddInvalidationObserver(base::Bind( + &WakeEventPageNativeHandler::DeleteSelf, base::Unretained(this))); + }; + + ~WakeEventPageNativeHandler() override {} + + private: + void DeleteSelf() { + Invalidate(); + delete this; + } + + // Called by JavaScript with a single argument, the function to call when the + // event page has been woken. + void DoWakeEventPage(const v8::FunctionCallbackInfo<v8::Value>& args) { + CHECK_EQ(1, args.Length()); + CHECK(args[0]->IsFunction()); + v8::Global<v8::Function> callback(args.GetIsolate(), + args[0].As<v8::Function>()); + + const std::string& extension_id = context()->GetExtensionID(); + CHECK(!extension_id.empty()); + + make_request_.Run( + extension_id, + base::Bind(&WakeEventPageNativeHandler::OnEventPageIsAwake, + weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback))); + } + + void OnEventPageIsAwake(v8::Global<v8::Function> callback, bool success) { + v8::Isolate* isolate = context()->isolate(); + v8::HandleScope handle_scope(isolate); + v8::Local<v8::Value> args[] = { + v8::Boolean::New(isolate, success), + }; + context()->CallFunction(v8::Local<v8::Function>::New(isolate, callback), + arraysize(args), args); + } + + MakeRequestCallback make_request_; + base::WeakPtrFactory<WakeEventPageNativeHandler> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(WakeEventPageNativeHandler); +}; + +// static +WakeEventPage* WakeEventPage::Get() { + return g_instance.Pointer(); +} + +void WakeEventPage::Init(content::RenderThread* render_thread) { + DCHECK(render_thread); + DCHECK_EQ(content::RenderThread::Get(), render_thread); + DCHECK(!message_filter_); + + message_filter_ = render_thread->GetSyncMessageFilter(); + render_thread->AddObserver(this); +} + +v8::Local<v8::Function> WakeEventPage::GetForContext(ScriptContext* context) { + DCHECK(message_filter_); + + v8::Isolate* isolate = context->isolate(); + v8::EscapableHandleScope handle_scope(isolate); + v8::Handle<v8::Context> v8_context = context->v8_context(); + v8::Context::Scope context_scope(v8_context); + + // Cache the imported function as a hidden property on the global object of + // |v8_context|. Creating it isn't free. + v8::Local<v8::String> kWakeEventPageKey = + ToV8StringUnsafe(isolate, "WakeEventPage"); + v8::Local<v8::Value> wake_event_page = + v8_context->Global()->GetHiddenValue(kWakeEventPageKey); + + if (wake_event_page.IsEmpty()) { + // Implement this using a NativeHandler, which requires a function name + // (arbitrary in this case). Handles own lifetime. + const char* kFunctionName = "WakeEventPage"; + WakeEventPageNativeHandler* native_handler = new WakeEventPageNativeHandler( + context, kFunctionName, base::Bind(&WakeEventPage::MakeRequest, + weak_ptr_factory_.GetWeakPtr())); + + // Extract and cache the wake-event-page function from the native handler. + wake_event_page = GetPropertyUnsafe( + v8_context, native_handler->NewInstance(), kFunctionName); + v8_context->Global()->SetHiddenValue(kWakeEventPageKey, wake_event_page); + } + + CHECK(wake_event_page->IsFunction()); + return handle_scope.Escape(wake_event_page.As<v8::Function>()); +} + +WakeEventPage::RequestData::RequestData(const OnResponseCallback& on_response) + : on_response(on_response) {} + +WakeEventPage::RequestData::~RequestData() {} + +WakeEventPage::WakeEventPage() : weak_ptr_factory_(this) {} + +WakeEventPage::~WakeEventPage() {} + +void WakeEventPage::MakeRequest(const std::string& extension_id, + const OnResponseCallback& on_response) { + static base::AtomicSequenceNumber sequence_number; + int request_id = sequence_number.GetNext(); + requests_.set(request_id, make_scoped_ptr(new RequestData(on_response))); + message_filter_->Send( + new ExtensionHostMsg_WakeEventPage(request_id, extension_id)); +} + +bool WakeEventPage::OnControlMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(WakeEventPage, message) + IPC_MESSAGE_HANDLER(ExtensionMsg_WakeEventPageResponse, + OnWakeEventPageResponse) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void WakeEventPage::OnWakeEventPageResponse(int request_id, bool success) { + scoped_ptr<RequestData> request_data = requests_.take(request_id); + CHECK(request_data); + request_data->on_response.Run(success); +} + +} // namespace extensions diff --git a/extensions/renderer/wake_event_page.h b/extensions/renderer/wake_event_page.h new file mode 100644 index 0000000..38ceda4f --- /dev/null +++ b/extensions/renderer/wake_event_page.h @@ -0,0 +1,108 @@ +// Copyright 2015 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. + +#ifndef EXTENSIONS_RENDERER_WAKE_EVENT_PAGE_H_ +#define EXTENSIONS_RENDERER_WAKE_EVENT_PAGE_H_ + +#include <string> + +#include "base/callback.h" +#include "base/containers/scoped_ptr_hash_map.h" +#include "base/lazy_instance.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "content/public/renderer/render_process_observer.h" +#include "ipc/ipc_sync_message_filter.h" +#include "v8/include/v8.h" + +namespace content { +class RenderThread; +} + +namespace extensions { +class ScriptContext; + +// This class implements the wake-event-page JavaScript function, which wakes +// an event page and runs a callback when done. +// +// Note, the function will do a round trip to the browser even if event page is +// open. Any optimisation to prevent this must be at the JavaScript level. +class WakeEventPage : public content::RenderProcessObserver { + public: + WakeEventPage(); + ~WakeEventPage() override; + + // Returns the single instance of the WakeEventPage object. + // + // Thread safe. + static WakeEventPage* Get(); + + // Initializes the WakeEventPage. + // + // This must be called before any bindings are installed, and must be called + // on the render thread. + void Init(content::RenderThread* render_thread); + + // Returns the wake-event-page function bound to a given context. The + // function will be cached as a hidden value in the context's global object. + // + // To mix C++ and JavaScript, example usage might be: + // + // WakeEventPage::Get().GetForContext(context)(function() { + // ... + // }); + // + // Thread safe. + v8::Local<v8::Function> GetForContext(ScriptContext* context); + + private: + class WakeEventPageNativeHandler; + + // The response from an ExtensionHostMsg_WakeEvent call, passed true if the + // call was successful, false on failure. + using OnResponseCallback = base::Callback<void(bool)>; + + // Makes an ExtensionHostMsg_WakeEvent request for an extension ID. The + // second argument is a callback to run when the request has completed. + using MakeRequestCallback = + base::Callback<void(const std::string&, const OnResponseCallback&)>; + + // For |requests_|. + struct RequestData { + explicit RequestData(const OnResponseCallback& on_response); + ~RequestData(); + OnResponseCallback on_response; + }; + + // Runs |on_response|, passing it |success|. + static void RunOnResponseWithResult(const OnResponseCallback& on_response, + bool success); + + // Sends the ExtensionHostMsg_WakeEvent IPC for |extension_id|, and + // updates |requests_| bookkeeping. + void MakeRequest(const std::string& extension_id, + const OnResponseCallback& on_response); + + // content::RenderProcessObserver: + bool OnControlMessageReceived(const IPC::Message& message) override; + + // OnControlMessageReceived handlers: + void OnWakeEventPageResponse(int request_id, bool success); + + // IPC sender. Belongs to the render thread, but thread safe. + scoped_refptr<IPC::SyncMessageFilter> message_filter_; + + // All in-flight requests, keyed by request ID. + base::ScopedPtrHashMap<int, scoped_ptr<RequestData>> requests_; + + base::WeakPtrFactory<WakeEventPage> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(WakeEventPage); +}; + +} // namespace extensions + +#endif // EXTENSIONS_RENDERER_WAKE_EVENT_PAGE_H_ |