summaryrefslogtreecommitdiffstats
path: root/extensions/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/renderer')
-rw-r--r--extensions/renderer/dispatcher.cc6
-rw-r--r--extensions/renderer/resources/test_custom_bindings.js5
-rw-r--r--extensions/renderer/test_native_handler.cc24
-rw-r--r--extensions/renderer/test_native_handler.h28
-rw-r--r--extensions/renderer/wake_event_page.cc173
-rw-r--r--extensions/renderer/wake_event_page.h108
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_