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"
9 #include "base/bind_helpers.h"
10 #include "base/logging.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "content/public/renderer/render_thread.h"
13 #include "extensions/common/extension_messages.h"
14 #include "extensions/renderer/object_backed_native_handler.h"
15 #include "extensions/renderer/script_context.h"
16 #include "extensions/renderer/v8_helpers.h"
17 #include "ipc/ipc_message.h"
18 #include "ipc/ipc_message_macros.h"
20 namespace extensions
{
22 using namespace v8_helpers
;
26 base::LazyInstance
<WakeEventPage
> g_instance
= LAZY_INSTANCE_INITIALIZER
;
30 class WakeEventPage::WakeEventPageNativeHandler
31 : public ObjectBackedNativeHandler
{
33 // Handles own lifetime.
34 WakeEventPageNativeHandler(ScriptContext
* context
,
35 const std::string
& name
,
36 const MakeRequestCallback
& make_request
)
37 : ObjectBackedNativeHandler(context
),
38 make_request_(make_request
),
39 weak_ptr_factory_(this) {
40 // Use Unretained not a WeakPtr because RouteFunction is tied to the
41 // lifetime of this, so there is no way for DoWakeEventPage to be called
43 RouteFunction(name
, base::Bind(&WakeEventPageNativeHandler::DoWakeEventPage
,
44 base::Unretained(this)));
45 // Delete self on invalidation. base::Unretained because by definition this
46 // can't be deleted before it's deleted.
47 context
->AddInvalidationObserver(base::Bind(
48 &WakeEventPageNativeHandler::DeleteSelf
, base::Unretained(this)));
51 ~WakeEventPageNativeHandler() override
{}
59 // Called by JavaScript with a single argument, the function to call when the
60 // event page has been woken.
61 void DoWakeEventPage(const v8::FunctionCallbackInfo
<v8::Value
>& args
) {
62 CHECK_EQ(1, args
.Length());
63 CHECK(args
[0]->IsFunction());
64 v8::Global
<v8::Function
> callback(args
.GetIsolate(),
65 args
[0].As
<v8::Function
>());
67 const std::string
& extension_id
= context()->GetExtensionID();
68 CHECK(!extension_id
.empty());
72 base::Bind(&WakeEventPageNativeHandler::OnEventPageIsAwake
,
73 weak_ptr_factory_
.GetWeakPtr(), base::Passed(&callback
)));
76 void OnEventPageIsAwake(v8::Global
<v8::Function
> callback
, bool success
) {
77 v8::Isolate
* isolate
= context()->isolate();
78 v8::HandleScope
handle_scope(isolate
);
79 v8::Local
<v8::Value
> args
[] = {
80 v8::Boolean::New(isolate
, success
),
82 context()->CallFunction(v8::Local
<v8::Function
>::New(isolate
, callback
),
83 arraysize(args
), args
);
86 MakeRequestCallback make_request_
;
87 base::WeakPtrFactory
<WakeEventPageNativeHandler
> weak_ptr_factory_
;
89 DISALLOW_COPY_AND_ASSIGN(WakeEventPageNativeHandler
);
93 WakeEventPage
* WakeEventPage::Get() {
94 return g_instance
.Pointer();
97 void WakeEventPage::Init(content::RenderThread
* render_thread
) {
98 DCHECK(render_thread
);
99 DCHECK_EQ(content::RenderThread::Get(), render_thread
);
100 DCHECK(!message_filter_
);
102 message_filter_
= render_thread
->GetSyncMessageFilter();
103 render_thread
->AddObserver(this);
106 v8::Local
<v8::Function
> WakeEventPage::GetForContext(ScriptContext
* context
) {
107 DCHECK(message_filter_
);
109 v8::Isolate
* isolate
= context
->isolate();
110 v8::EscapableHandleScope
handle_scope(isolate
);
111 v8::Handle
<v8::Context
> v8_context
= context
->v8_context();
112 v8::Context::Scope
context_scope(v8_context
);
114 // Cache the imported function as a hidden property on the global object of
115 // |v8_context|. Creating it isn't free.
116 v8::Local
<v8::String
> kWakeEventPageKey
=
117 ToV8StringUnsafe(isolate
, "WakeEventPage");
118 v8::Local
<v8::Value
> wake_event_page
=
119 v8_context
->Global()->GetHiddenValue(kWakeEventPageKey
);
121 if (wake_event_page
.IsEmpty()) {
122 // Implement this using a NativeHandler, which requires a function name
123 // (arbitrary in this case). Handles own lifetime.
124 const char* kFunctionName
= "WakeEventPage";
125 WakeEventPageNativeHandler
* native_handler
= new WakeEventPageNativeHandler(
126 context
, kFunctionName
, base::Bind(&WakeEventPage::MakeRequest
,
127 weak_ptr_factory_
.GetWeakPtr()));
129 // Extract and cache the wake-event-page function from the native handler.
130 wake_event_page
= GetPropertyUnsafe(
131 v8_context
, native_handler
->NewInstance(), kFunctionName
);
132 v8_context
->Global()->SetHiddenValue(kWakeEventPageKey
, wake_event_page
);
135 CHECK(wake_event_page
->IsFunction());
136 return handle_scope
.Escape(wake_event_page
.As
<v8::Function
>());
139 WakeEventPage::RequestData::RequestData(const OnResponseCallback
& on_response
)
140 : on_response(on_response
) {}
142 WakeEventPage::RequestData::~RequestData() {}
144 WakeEventPage::WakeEventPage() : weak_ptr_factory_(this) {}
146 WakeEventPage::~WakeEventPage() {}
148 void WakeEventPage::MakeRequest(const std::string
& extension_id
,
149 const OnResponseCallback
& on_response
) {
150 static base::AtomicSequenceNumber sequence_number
;
151 int request_id
= sequence_number
.GetNext();
152 requests_
.set(request_id
, make_scoped_ptr(new RequestData(on_response
)));
153 message_filter_
->Send(
154 new ExtensionHostMsg_WakeEventPage(request_id
, extension_id
));
157 bool WakeEventPage::OnControlMessageReceived(const IPC::Message
& message
) {
159 IPC_BEGIN_MESSAGE_MAP(WakeEventPage
, message
)
160 IPC_MESSAGE_HANDLER(ExtensionMsg_WakeEventPageResponse
,
161 OnWakeEventPageResponse
)
162 IPC_MESSAGE_UNHANDLED(handled
= false)
163 IPC_END_MESSAGE_MAP()
167 void WakeEventPage::OnWakeEventPageResponse(int request_id
, bool success
) {
168 scoped_ptr
<RequestData
> request_data
= requests_
.take(request_id
);
170 request_data
->on_response
.Run(success
);
173 } // namespace extensions