1 // Copyright (c) 2013 Intel Corporation. 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 "xwalk/extensions/browser/xwalk_extension_process_host.h"
9 #include "base/command_line.h"
10 #include "base/logging.h"
11 #include "base/files/file_path.h"
12 #include "content/public/browser/browser_child_process_host.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/common/child_process_host.h"
16 #include "content/public/common/process_type.h"
17 #include "content/public/common/content_switches.h"
19 #include "content/public/common/sandboxed_process_launcher_delegate.h"
21 #include "ipc/ipc_message.h"
22 #include "ipc/ipc_switches.h"
23 #include "xwalk/extensions/common/xwalk_extension_messages.h"
24 #include "xwalk/extensions/common/xwalk_extension_switches.h"
26 using content::BrowserThread;
29 namespace extensions {
31 // This filter is used by ExtensionProcessHost to intercept when Render Process
32 // ask for the Extension Channel handle (that is created by extension process).
33 class XWalkExtensionProcessHost::RenderProcessMessageFilter
34 : public IPC::ChannelProxy::MessageFilter {
36 explicit RenderProcessMessageFilter(XWalkExtensionProcessHost* eph)
39 // This exists to fulfill the requirement for delayed reply handling, since it
40 // needs to send a message back if the parameters couldn't be correctly read
41 // from the original message received. See DispatchDealyReplyWithSendParams().
42 bool Send(IPC::Message* message) {
44 return eph_->render_process_host_->Send(message);
54 // IPC::ChannelProxy::MessageFilter implementation.
55 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
57 IPC_BEGIN_MESSAGE_MAP(RenderProcessMessageFilter, message)
58 IPC_MESSAGE_HANDLER_DELAY_REPLY(
59 XWalkExtensionProcessHostMsg_GetExtensionProcessChannel,
60 OnGetExtensionProcessChannel)
61 IPC_MESSAGE_UNHANDLED(handled = false)
66 void OnGetExtensionProcessChannel(IPC::Message* reply) {
67 scoped_ptr<IPC::Message> scoped_reply(reply);
69 eph_->OnGetExtensionProcessChannel(scoped_reply.Pass());
72 virtual ~RenderProcessMessageFilter() {}
74 XWalkExtensionProcessHost* eph_;
78 class ExtensionSandboxedProcessLauncherDelegate
79 : public content::SandboxedProcessLauncherDelegate {
81 ExtensionSandboxedProcessLauncherDelegate() {}
82 virtual ~ExtensionSandboxedProcessLauncherDelegate() {}
84 virtual void ShouldSandbox(bool* in_sandbox) OVERRIDE {
89 DISALLOW_COPY_AND_ASSIGN(ExtensionSandboxedProcessLauncherDelegate);
93 bool XWalkExtensionProcessHost::Delegate::OnRegisterPermissions(
94 int render_process_id,
95 const std::string& extension_name,
96 const std::string& perm_table) {
100 XWalkExtensionProcessHost::XWalkExtensionProcessHost(
101 content::RenderProcessHost* render_process_host,
102 const base::FilePath& external_extensions_path,
103 XWalkExtensionProcessHost::Delegate* delegate,
104 const base::ValueMap& runtime_variables)
105 : ep_rp_channel_handle_(""),
106 render_process_host_(render_process_host),
107 render_process_message_filter_(new RenderProcessMessageFilter(this)),
108 external_extensions_path_(external_extensions_path),
109 is_extension_process_channel_ready_(false),
111 runtime_variables_(runtime_variables) {
112 render_process_host_->GetChannel()->AddFilter(render_process_message_filter_);
113 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
114 base::Bind(&XWalkExtensionProcessHost::StartProcess,
115 base::Unretained(this)));
118 XWalkExtensionProcessHost::~XWalkExtensionProcessHost() {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
120 render_process_message_filter_->Invalidate();
126 void ToListValue(base::ValueMap* vm, base::ListValue* lv) {
129 for (base::ValueMap::iterator it = vm->begin(); it != vm->end(); it++) {
130 base::DictionaryValue* dv = new base::DictionaryValue();
131 dv->Set(it->first, it->second);
138 void XWalkExtensionProcessHost::StartProcess() {
139 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
142 process_.reset(content::BrowserChildProcessHost::Create(
143 content::PROCESS_TYPE_CONTENT_END, this));
145 std::string channel_id = process_->GetHost()->CreateChannel();
146 CHECK(!channel_id.empty());
148 base::FilePath exe_path = content::ChildProcessHost::GetChildPath(
149 content::ChildProcessHost::CHILD_NORMAL);
150 scoped_ptr<CommandLine> cmd_line(new CommandLine(exe_path));
151 cmd_line->AppendSwitchASCII(switches::kProcessType,
152 switches::kXWalkExtensionProcess);
153 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
156 new ExtensionSandboxedProcessLauncherDelegate(),
157 #elif defined(OS_POSIX)
158 false, base::EnvironmentMap(),
162 base::ListValue runtime_variables_lv;
163 ToListValue(&const_cast<base::ValueMap&>(runtime_variables_),
164 &runtime_variables_lv);
165 process_->GetHost()->Send(new XWalkExtensionProcessMsg_RegisterExtensions(
166 external_extensions_path_, runtime_variables_lv));
169 void XWalkExtensionProcessHost::StopProcess() {
174 void XWalkExtensionProcessHost::OnGetExtensionProcessChannel(
175 scoped_ptr<IPC::Message> reply) {
176 pending_reply_for_render_process_ = reply.Pass();
177 ReplyChannelHandleToRenderProcess();
180 bool XWalkExtensionProcessHost::OnMessageReceived(const IPC::Message& message) {
182 IPC_BEGIN_MESSAGE_MAP(XWalkExtensionProcessHost, message)
184 XWalkExtensionProcessHostMsg_RenderProcessChannelCreated,
185 OnRenderChannelCreated)
186 IPC_MESSAGE_HANDLER_DELAY_REPLY(
187 XWalkExtensionProcessHostMsg_CheckAPIAccessControl,
188 OnCheckAPIAccessControl)
190 XWalkExtensionProcessHostMsg_RegisterPermissions,
191 OnRegisterPermissions)
192 IPC_MESSAGE_UNHANDLED(handled = false)
193 IPC_END_MESSAGE_MAP()
197 void XWalkExtensionProcessHost::OnChannelError() {
198 // This function is called just before
199 // BrowserChildProcessHostImpl::OnChildDisconnected gets called. Please refer
200 // to ChildProcessHostImpl::OnChannelError() from child_process_host_impl.cc.
201 // This means that content::BrowserChildProcessHost (process_, in our case)
202 // is about to delete its delegate, which is us!
203 // We should alert our XWalkExtensionProcessHost::Delegate, since it will
204 // most likely have a pointer to us that needs to be invalidated.
206 VLOG(1) << "\n\nExtensionProcess crashed";
208 delegate_->OnExtensionProcessDied(this, render_process_host_->GetID());
211 void XWalkExtensionProcessHost::OnProcessLaunched() {
212 VLOG(1) << "\n\nExtensionProcess was started!";
215 void XWalkExtensionProcessHost::OnRenderChannelCreated(
216 const IPC::ChannelHandle& handle) {
217 is_extension_process_channel_ready_ = true;
218 ep_rp_channel_handle_ = handle;
219 ReplyChannelHandleToRenderProcess();
222 void XWalkExtensionProcessHost::ReplyChannelHandleToRenderProcess() {
223 // Replying the channel handle to RP depends on two events:
224 // - EP already notified EPH that new channel was created (for RP<->EP).
225 // - RP already asked for the channel handle.
227 // The order for this events is not determined, so we call this function from
228 // both, and the second execution will send the reply.
229 if (!is_extension_process_channel_ready_
230 || !pending_reply_for_render_process_)
233 XWalkExtensionProcessHostMsg_GetExtensionProcessChannel::WriteReplyParams(
234 pending_reply_for_render_process_.get(), ep_rp_channel_handle_);
236 render_process_host_->Send(pending_reply_for_render_process_.release());
239 void XWalkExtensionProcessHost::ReplyAccessControlToExtension(
240 IPC::Message* reply_msg,
241 RuntimePermission perm) {
242 XWalkExtensionProcessHostMsg_CheckAPIAccessControl
243 ::WriteReplyParams(reply_msg, perm);
247 void XWalkExtensionProcessHost::OnCheckAPIAccessControl(
248 const std::string& extension_name,
249 const std::string& api_name, IPC::Message* reply_msg) {
251 delegate_->OnCheckAPIAccessControl(render_process_host_->GetID(),
252 extension_name, api_name,
253 base::Bind(&XWalkExtensionProcessHost::ReplyAccessControlToExtension,
254 base::Unretained(this),
258 void XWalkExtensionProcessHost::OnRegisterPermissions(
259 const std::string& extension_name,
260 const std::string& perm_table, bool* result) {
262 *result = delegate_->OnRegisterPermissions(
263 render_process_host_->GetID(), extension_name, perm_table);
266 bool XWalkExtensionProcessHost::Send(IPC::Message* msg) {
267 return process_->GetHost()->Send(msg);
270 } // namespace extensions