Remove linux_chromium_gn_dbg from the chromium CQ.
[chromium-blink-merge.git] / extensions / renderer / wake_event_page.cc
blob7a64d1af32691155c4ea72ea22b50d1e3ba0a816
1 // Copyright 2015 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.
5 #include "extensions/renderer/wake_event_page.h"
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/bind_helpers.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "content/public/child/worker_thread.h"
14 #include "content/public/renderer/render_thread.h"
15 #include "extensions/common/extension_messages.h"
16 #include "extensions/renderer/object_backed_native_handler.h"
17 #include "extensions/renderer/script_context.h"
18 #include "extensions/renderer/v8_helpers.h"
19 #include "ipc/ipc_message.h"
20 #include "ipc/ipc_message_macros.h"
22 namespace extensions {
24 using namespace v8_helpers;
26 namespace {
28 base::LazyInstance<WakeEventPage> g_instance = LAZY_INSTANCE_INITIALIZER;
30 } // namespace
32 class WakeEventPage::WakeEventPageNativeHandler
33 : public ObjectBackedNativeHandler {
34 public:
35 // Handles own lifetime.
36 WakeEventPageNativeHandler(ScriptContext* context,
37 const std::string& name,
38 const MakeRequestCallback& make_request)
39 : ObjectBackedNativeHandler(context),
40 make_request_(make_request),
41 weak_ptr_factory_(this) {
42 // Use Unretained not a WeakPtr because RouteFunction is tied to the
43 // lifetime of this, so there is no way for DoWakeEventPage to be called
44 // after destruction.
45 RouteFunction(name, base::Bind(&WakeEventPageNativeHandler::DoWakeEventPage,
46 base::Unretained(this)));
47 // Delete self on invalidation. base::Unretained because by definition this
48 // can't be deleted before it's deleted.
49 context->AddInvalidationObserver(base::Bind(
50 &WakeEventPageNativeHandler::DeleteSelf, base::Unretained(this)));
53 ~WakeEventPageNativeHandler() override {}
55 private:
56 void DeleteSelf() {
57 Invalidate();
58 delete this;
61 // Called by JavaScript with a single argument, the function to call when the
62 // event page has been woken.
63 void DoWakeEventPage(const v8::FunctionCallbackInfo<v8::Value>& args) {
64 CHECK_EQ(1, args.Length());
65 CHECK(args[0]->IsFunction());
66 v8::Global<v8::Function> callback(args.GetIsolate(),
67 args[0].As<v8::Function>());
69 const std::string& extension_id = context()->GetExtensionID();
70 CHECK(!extension_id.empty());
72 make_request_.Run(
73 extension_id,
74 base::Bind(&WakeEventPageNativeHandler::OnEventPageIsAwake,
75 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
78 void OnEventPageIsAwake(v8::Global<v8::Function> callback, bool success) {
79 v8::Isolate* isolate = context()->isolate();
80 v8::HandleScope handle_scope(isolate);
81 v8::Local<v8::Value> args[] = {
82 v8::Boolean::New(isolate, success),
84 context()->CallFunction(v8::Local<v8::Function>::New(isolate, callback),
85 arraysize(args), args);
88 MakeRequestCallback make_request_;
89 base::WeakPtrFactory<WakeEventPageNativeHandler> weak_ptr_factory_;
91 DISALLOW_COPY_AND_ASSIGN(WakeEventPageNativeHandler);
94 // static
95 WakeEventPage* WakeEventPage::Get() {
96 return g_instance.Pointer();
99 void WakeEventPage::Init(content::RenderThread* render_thread) {
100 DCHECK(render_thread);
101 DCHECK_EQ(content::RenderThread::Get(), render_thread);
102 DCHECK(!message_filter_);
104 message_filter_ = render_thread->GetSyncMessageFilter();
105 render_thread->AddObserver(this);
108 v8::Local<v8::Function> WakeEventPage::GetForContext(ScriptContext* context) {
109 DCHECK(message_filter_);
111 v8::Isolate* isolate = context->isolate();
112 v8::EscapableHandleScope handle_scope(isolate);
113 v8::Handle<v8::Context> v8_context = context->v8_context();
114 v8::Context::Scope context_scope(v8_context);
116 // Cache the imported function as a hidden property on the global object of
117 // |v8_context|. Creating it isn't free.
118 v8::Local<v8::String> kWakeEventPageKey =
119 ToV8StringUnsafe(isolate, "WakeEventPage");
120 v8::Local<v8::Value> wake_event_page =
121 v8_context->Global()->GetHiddenValue(kWakeEventPageKey);
123 if (wake_event_page.IsEmpty()) {
124 // Implement this using a NativeHandler, which requires a function name
125 // (arbitrary in this case). Handles own lifetime.
126 const char* kFunctionName = "WakeEventPage";
127 WakeEventPageNativeHandler* native_handler = new WakeEventPageNativeHandler(
128 context, kFunctionName, base::Bind(&WakeEventPage::MakeRequest,
129 // Safe, owned by a LazyInstance.
130 base::Unretained(this)));
132 // Extract and cache the wake-event-page function from the native handler.
133 wake_event_page = GetPropertyUnsafe(
134 v8_context, native_handler->NewInstance(), kFunctionName);
135 v8_context->Global()->SetHiddenValue(kWakeEventPageKey, wake_event_page);
138 CHECK(wake_event_page->IsFunction());
139 return handle_scope.Escape(wake_event_page.As<v8::Function>());
142 WakeEventPage::RequestData::RequestData(int thread_id,
143 const OnResponseCallback& on_response)
144 : thread_id(thread_id), on_response(on_response) {}
146 WakeEventPage::RequestData::~RequestData() {}
148 WakeEventPage::WakeEventPage() {}
150 WakeEventPage::~WakeEventPage() {}
152 void WakeEventPage::MakeRequest(const std::string& extension_id,
153 const OnResponseCallback& on_response) {
154 static base::AtomicSequenceNumber sequence_number;
155 int request_id = sequence_number.GetNext();
157 scoped_ptr<RequestData> request_data(
158 new RequestData(content::WorkerThread::GetCurrentId(), on_response));
159 base::AutoLock lock(requests_lock_);
160 requests_.set(request_id, request_data.Pass());
162 message_filter_->Send(
163 new ExtensionHostMsg_WakeEventPage(request_id, extension_id));
166 bool WakeEventPage::OnControlMessageReceived(const IPC::Message& message) {
167 bool handled = true;
168 IPC_BEGIN_MESSAGE_MAP(WakeEventPage, message)
169 IPC_MESSAGE_HANDLER(ExtensionMsg_WakeEventPageResponse,
170 OnWakeEventPageResponse)
171 IPC_MESSAGE_UNHANDLED(handled = false)
172 IPC_END_MESSAGE_MAP()
173 return handled;
176 void WakeEventPage::OnWakeEventPageResponse(int request_id, bool success) {
177 scoped_ptr<RequestData> request_data;
179 base::AutoLock lock(requests_lock_);
180 request_data = requests_.take(request_id);
182 CHECK(request_data) << "No request with ID " << request_id;
183 if (request_data->thread_id == 0) {
184 // Thread ID of 0 means it wasn't called on a worker thread, so safe to
185 // call immediately.
186 request_data->on_response.Run(success);
187 } else {
188 content::WorkerThread::PostTask(
189 request_data->thread_id,
190 base::Bind(request_data->on_response, success));
194 } // namespace extensions