blob: 2118929ff15394fbc6c8aa9fc8a8ec7f7625cbcd [file] [log] [blame]
kalman12033f122015-08-21 19:30:131// 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.
4
5#include "extensions/renderer/wake_event_page.h"
6
dchengf6f80662016-04-20 20:26:047#include <memory>
dchenge59eca1602015-12-18 17:48:008#include <utility>
9
kalman12033f122015-08-21 19:30:1310#include "base/atomic_sequence_num.h"
11#include "base/bind.h"
12#include "base/bind_helpers.h"
kalman6f984ae2015-09-18 17:21:5813#include "base/lazy_instance.h"
kalman12033f122015-08-21 19:30:1314#include "base/logging.h"
avi2d124c02015-12-23 06:36:4215#include "base/macros.h"
avi7368a3e2016-12-29 01:26:2816#include "base/memory/ptr_util.h"
kalman6f984ae2015-09-18 17:21:5817#include "content/public/child/worker_thread.h"
kalman12033f122015-08-21 19:30:1318#include "content/public/renderer/render_thread.h"
19#include "extensions/common/extension_messages.h"
20#include "extensions/renderer/object_backed_native_handler.h"
21#include "extensions/renderer/script_context.h"
22#include "extensions/renderer/v8_helpers.h"
23#include "ipc/ipc_message.h"
24#include "ipc/ipc_message_macros.h"
25
26namespace extensions {
27
28using namespace v8_helpers;
29
30namespace {
31
scottmg5e65e3a2017-03-08 08:48:4632base::LazyInstance<WakeEventPage>::DestructorAtExit g_instance =
33 LAZY_INSTANCE_INITIALIZER;
kalman12033f122015-08-21 19:30:1334
35} // namespace
36
37class WakeEventPage::WakeEventPageNativeHandler
38 : public ObjectBackedNativeHandler {
39 public:
40 // Handles own lifetime.
41 WakeEventPageNativeHandler(ScriptContext* context,
42 const std::string& name,
43 const MakeRequestCallback& make_request)
44 : ObjectBackedNativeHandler(context),
45 make_request_(make_request),
46 weak_ptr_factory_(this) {
47 // Use Unretained not a WeakPtr because RouteFunction is tied to the
48 // lifetime of this, so there is no way for DoWakeEventPage to be called
49 // after destruction.
50 RouteFunction(name, base::Bind(&WakeEventPageNativeHandler::DoWakeEventPage,
51 base::Unretained(this)));
52 // Delete self on invalidation. base::Unretained because by definition this
53 // can't be deleted before it's deleted.
54 context->AddInvalidationObserver(base::Bind(
55 &WakeEventPageNativeHandler::DeleteSelf, base::Unretained(this)));
56 };
57
58 ~WakeEventPageNativeHandler() override {}
59
60 private:
61 void DeleteSelf() {
62 Invalidate();
63 delete this;
64 }
65
66 // Called by JavaScript with a single argument, the function to call when the
67 // event page has been woken.
68 void DoWakeEventPage(const v8::FunctionCallbackInfo<v8::Value>& args) {
69 CHECK_EQ(1, args.Length());
70 CHECK(args[0]->IsFunction());
71 v8::Global<v8::Function> callback(args.GetIsolate(),
72 args[0].As<v8::Function>());
73
74 const std::string& extension_id = context()->GetExtensionID();
75 CHECK(!extension_id.empty());
76
77 make_request_.Run(
78 extension_id,
79 base::Bind(&WakeEventPageNativeHandler::OnEventPageIsAwake,
80 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
81 }
82
83 void OnEventPageIsAwake(v8::Global<v8::Function> callback, bool success) {
84 v8::Isolate* isolate = context()->isolate();
85 v8::HandleScope handle_scope(isolate);
86 v8::Local<v8::Value> args[] = {
87 v8::Boolean::New(isolate, success),
88 };
rdevlin.cronina3b46002016-10-10 20:21:4489 context()->SafeCallFunction(v8::Local<v8::Function>::New(isolate, callback),
90 arraysize(args), args);
kalman12033f122015-08-21 19:30:1391 }
92
93 MakeRequestCallback make_request_;
94 base::WeakPtrFactory<WakeEventPageNativeHandler> weak_ptr_factory_;
95
96 DISALLOW_COPY_AND_ASSIGN(WakeEventPageNativeHandler);
97};
98
99// static
100WakeEventPage* WakeEventPage::Get() {
101 return g_instance.Pointer();
102}
103
104void WakeEventPage::Init(content::RenderThread* render_thread) {
105 DCHECK(render_thread);
106 DCHECK_EQ(content::RenderThread::Get(), render_thread);
107 DCHECK(!message_filter_);
108
109 message_filter_ = render_thread->GetSyncMessageFilter();
110 render_thread->AddObserver(this);
111}
112
113v8::Local<v8::Function> WakeEventPage::GetForContext(ScriptContext* context) {
114 DCHECK(message_filter_);
115
116 v8::Isolate* isolate = context->isolate();
117 v8::EscapableHandleScope handle_scope(isolate);
118 v8::Handle<v8::Context> v8_context = context->v8_context();
119 v8::Context::Scope context_scope(v8_context);
120
121 // Cache the imported function as a hidden property on the global object of
122 // |v8_context|. Creating it isn't free.
jochen300abe232015-11-06 21:17:53123 v8::Local<v8::Private> kWakeEventPageKey =
124 v8::Private::ForApi(isolate, ToV8StringUnsafe(isolate, "WakeEventPage"));
125 v8::Local<v8::Value> wake_event_page;
126 if (!v8_context->Global()
127 ->GetPrivate(v8_context, kWakeEventPageKey)
128 .ToLocal(&wake_event_page) ||
129 wake_event_page->IsUndefined()) {
kalman12033f122015-08-21 19:30:13130 // Implement this using a NativeHandler, which requires a function name
131 // (arbitrary in this case). Handles own lifetime.
132 const char* kFunctionName = "WakeEventPage";
133 WakeEventPageNativeHandler* native_handler = new WakeEventPageNativeHandler(
134 context, kFunctionName, base::Bind(&WakeEventPage::MakeRequest,
kalman6f984ae2015-09-18 17:21:58135 // Safe, owned by a LazyInstance.
136 base::Unretained(this)));
kalman12033f122015-08-21 19:30:13137
138 // Extract and cache the wake-event-page function from the native handler.
139 wake_event_page = GetPropertyUnsafe(
140 v8_context, native_handler->NewInstance(), kFunctionName);
jochen300abe232015-11-06 21:17:53141 v8_context->Global()
142 ->SetPrivate(v8_context, kWakeEventPageKey, wake_event_page)
143 .FromJust();
kalman12033f122015-08-21 19:30:13144 }
145
146 CHECK(wake_event_page->IsFunction());
147 return handle_scope.Escape(wake_event_page.As<v8::Function>());
148}
149
kalman6f984ae2015-09-18 17:21:58150WakeEventPage::RequestData::RequestData(int thread_id,
151 const OnResponseCallback& on_response)
152 : thread_id(thread_id), on_response(on_response) {}
kalman12033f122015-08-21 19:30:13153
154WakeEventPage::RequestData::~RequestData() {}
155
kalman6f984ae2015-09-18 17:21:58156WakeEventPage::WakeEventPage() {}
kalman12033f122015-08-21 19:30:13157
158WakeEventPage::~WakeEventPage() {}
159
160void WakeEventPage::MakeRequest(const std::string& extension_id,
161 const OnResponseCallback& on_response) {
162 static base::AtomicSequenceNumber sequence_number;
163 int request_id = sequence_number.GetNext();
kalman6f984ae2015-09-18 17:21:58164 {
kalman6f984ae2015-09-18 17:21:58165 base::AutoLock lock(requests_lock_);
avi7368a3e2016-12-29 01:26:28166 requests_[request_id] = base::MakeUnique<RequestData>(
167 content::WorkerThread::GetCurrentId(), on_response);
kalman6f984ae2015-09-18 17:21:58168 }
kalman12033f122015-08-21 19:30:13169 message_filter_->Send(
170 new ExtensionHostMsg_WakeEventPage(request_id, extension_id));
171}
172
173bool WakeEventPage::OnControlMessageReceived(const IPC::Message& message) {
174 bool handled = true;
175 IPC_BEGIN_MESSAGE_MAP(WakeEventPage, message)
176 IPC_MESSAGE_HANDLER(ExtensionMsg_WakeEventPageResponse,
177 OnWakeEventPageResponse)
178 IPC_MESSAGE_UNHANDLED(handled = false)
179 IPC_END_MESSAGE_MAP()
180 return handled;
181}
182
183void WakeEventPage::OnWakeEventPageResponse(int request_id, bool success) {
dchengf6f80662016-04-20 20:26:04184 std::unique_ptr<RequestData> request_data;
kalman6f984ae2015-09-18 17:21:58185 {
186 base::AutoLock lock(requests_lock_);
avi7368a3e2016-12-29 01:26:28187 auto it = requests_.find(request_id);
188 CHECK(it != requests_.end()) << "No request with ID " << request_id;
189 request_data = std::move(it->second);
190 requests_.erase(it);
kalman6f984ae2015-09-18 17:21:58191 }
kalman6f984ae2015-09-18 17:21:58192 if (request_data->thread_id == 0) {
193 // Thread ID of 0 means it wasn't called on a worker thread, so safe to
194 // call immediately.
195 request_data->on_response.Run(success);
196 } else {
197 content::WorkerThread::PostTask(
198 request_data->thread_id,
199 base::Bind(request_data->on_response, success));
200 }
kalman12033f122015-08-21 19:30:13201}
202
203} // namespace extensions