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"
18 #include "content/public/common/sandboxed_process_launcher_delegate.h"
19 #include "ipc/ipc_message.h"
20 #include "ipc/ipc_switches.h"
21 #include "ipc/message_filter.h"
22 #include "xwalk/extensions/common/xwalk_extension_messages.h"
23 #include "xwalk/extensions/common/xwalk_extension_switches.h"
24 #include "xwalk/runtime/browser/xwalk_runner.h"
25 #include "xwalk/runtime/common/xwalk_switches.h"
27 using content::BrowserThread;
30 namespace extensions {
32 // This filter is used by ExtensionProcessHost to intercept when Render Process
33 // ask for the Extension Channel handle (that is created by extension process).
34 class XWalkExtensionProcessHost::RenderProcessMessageFilter
35 : public IPC::MessageFilter {
37 explicit RenderProcessMessageFilter(XWalkExtensionProcessHost* eph)
40 // This exists to fulfill the requirement for delayed reply handling, since it
41 // needs to send a message back if the parameters couldn't be correctly read
42 // from the original message received. See DispatchDealyReplyWithSendParams().
43 bool Send(IPC::Message* message) {
45 return eph_->render_process_host_->Send(message);
55 // IPC::ChannelProxy::MessageFilter implementation.
56 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
58 IPC_BEGIN_MESSAGE_MAP(RenderProcessMessageFilter, message)
59 IPC_MESSAGE_HANDLER_DELAY_REPLY(
60 XWalkExtensionProcessHostMsg_GetExtensionProcessChannel,
61 OnGetExtensionProcessChannel)
62 IPC_MESSAGE_UNHANDLED(handled = false)
67 void OnGetExtensionProcessChannel(IPC::Message* reply) {
68 scoped_ptr<IPC::Message> scoped_reply(reply);
70 eph_->OnGetExtensionProcessChannel(scoped_reply.Pass());
73 virtual ~RenderProcessMessageFilter() {}
75 XWalkExtensionProcessHost* eph_;
78 class ExtensionSandboxedProcessLauncherDelegate
79 : public content::SandboxedProcessLauncherDelegate {
81 explicit ExtensionSandboxedProcessLauncherDelegate(
82 content::ChildProcessHost* host)
84 : ipc_fd_(host->TakeClientFileDescriptor())
87 virtual ~ExtensionSandboxedProcessLauncherDelegate() {}
90 virtual bool ShouldSandbox() OVERRIDE {
93 #elif defined(OS_POSIX)
94 virtual int GetIpcFd() OVERRIDE {
100 #if defined(OS_POSIX)
104 DISALLOW_COPY_AND_ASSIGN(ExtensionSandboxedProcessLauncherDelegate);
107 bool XWalkExtensionProcessHost::Delegate::OnRegisterPermissions(
108 int render_process_id,
109 const std::string& extension_name,
110 const std::string& perm_table) {
114 XWalkExtensionProcessHost::XWalkExtensionProcessHost(
115 content::RenderProcessHost* render_process_host,
116 const base::FilePath& external_extensions_path,
117 XWalkExtensionProcessHost::Delegate* delegate,
118 scoped_ptr<base::ValueMap> runtime_variables)
119 : ep_rp_channel_handle_(""),
120 render_process_host_(render_process_host),
121 render_process_message_filter_(new RenderProcessMessageFilter(this)),
122 external_extensions_path_(external_extensions_path),
123 is_extension_process_channel_ready_(false),
125 runtime_variables_(runtime_variables.Pass()) {
126 render_process_host_->GetChannel()->AddFilter(
127 render_process_message_filter_.get());
128 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
129 base::Bind(&XWalkExtensionProcessHost::StartProcess,
130 base::Unretained(this)));
133 XWalkExtensionProcessHost::~XWalkExtensionProcessHost() {
134 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
135 render_process_message_filter_->Invalidate();
141 void ToListValue(base::ValueMap* vm, base::ListValue* lv) {
144 for (base::ValueMap::iterator it = vm->begin(); it != vm->end(); it++) {
145 base::DictionaryValue* dv = new base::DictionaryValue();
146 dv->Set(it->first, it->second);
153 void XWalkExtensionProcessHost::StartProcess() {
154 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
155 CHECK(!process_ || !channel_);
157 if (XWalkRunner::GetInstance()->shared_process_mode_enabled()) {
158 #if defined(OS_LINUX)
159 std::string channel_id =
160 IPC::Channel::GenerateVerifiedChannelID(std::string());
161 channel_ = IPC::Channel::CreateServer(channel_id, this);
162 if (!channel_->Connect())
164 IPC::ChannelHandle channel_handle(channel_id,
165 base::FileDescriptor(channel_->TakeClientFileDescriptor(), true));
166 BrowserThread::PostTask(
167 BrowserThread::UI, FROM_HERE,
169 &XWalkExtensionProcessHost::Delegate::OnExtensionProcessCreated,
170 base::Unretained(delegate_), render_process_host_->GetID(),
174 #endif // #if defined(OS_LINUX)
176 process_.reset(content::BrowserChildProcessHost::Create(
177 content::PROCESS_TYPE_CONTENT_END, this));
179 std::string channel_id = process_->GetHost()->CreateChannel();
180 CHECK(!channel_id.empty());
182 CommandLine::StringType extension_cmd_prefix;
183 #if defined(OS_POSIX)
184 const CommandLine &browser_command_line = *CommandLine::ForCurrentProcess();
185 extension_cmd_prefix = browser_command_line.GetSwitchValueNative(
186 switches::kXWalkExtensionCmdPrefix);
189 #if defined(OS_LINUX)
190 int flags = extension_cmd_prefix.empty() ?
191 content::ChildProcessHost::CHILD_ALLOW_SELF :
192 content::ChildProcessHost::CHILD_NORMAL;
194 int flags = content::ChildProcessHost::CHILD_NORMAL;
197 base::FilePath exe_path = content::ChildProcessHost::GetChildPath(flags);
198 if (exe_path.empty())
201 scoped_ptr<CommandLine> cmd_line(new CommandLine(exe_path));
202 cmd_line->AppendSwitchASCII(switches::kProcessType,
203 switches::kXWalkExtensionProcess);
204 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
205 if (!extension_cmd_prefix.empty())
206 cmd_line->PrependWrapper(extension_cmd_prefix);
209 new ExtensionSandboxedProcessLauncherDelegate(process_->GetHost()),
213 base::ListValue runtime_variables_lv;
214 ToListValue(&const_cast<base::ValueMap&>(*runtime_variables_),
215 &runtime_variables_lv);
216 Send(new XWalkExtensionProcessMsg_RegisterExtensions(
217 external_extensions_path_, runtime_variables_lv));
220 void XWalkExtensionProcessHost::StopProcess() {
227 void XWalkExtensionProcessHost::OnGetExtensionProcessChannel(
228 scoped_ptr<IPC::Message> reply) {
229 pending_reply_for_render_process_ = reply.Pass();
230 ReplyChannelHandleToRenderProcess();
233 bool XWalkExtensionProcessHost::OnMessageReceived(const IPC::Message& message) {
235 IPC_BEGIN_MESSAGE_MAP(XWalkExtensionProcessHost, message)
237 XWalkExtensionProcessHostMsg_RenderProcessChannelCreated,
238 OnRenderChannelCreated)
239 IPC_MESSAGE_HANDLER_DELAY_REPLY(
240 XWalkExtensionProcessHostMsg_CheckAPIAccessControl,
241 OnCheckAPIAccessControl)
243 XWalkExtensionProcessHostMsg_RegisterPermissions,
244 OnRegisterPermissions)
245 IPC_MESSAGE_UNHANDLED(handled = false)
246 IPC_END_MESSAGE_MAP()
250 void XWalkExtensionProcessHost::OnChannelError() {
251 // This function is called just before
252 // BrowserChildProcessHostImpl::OnChildDisconnected gets called. Please refer
253 // to ChildProcessHostImpl::OnChannelError() from child_process_host_impl.cc.
254 // This means that content::BrowserChildProcessHost (process_, in our case)
255 // is about to delete its delegate, which is us!
256 // We should alert our XWalkExtensionProcessHost::Delegate, since it will
257 // most likely have a pointer to us that needs to be invalidated.
259 VLOG(1) << "\n\nExtensionProcess crashed";
261 delegate_->OnExtensionProcessDied(this, render_process_host_->GetID());
264 void XWalkExtensionProcessHost::OnProcessLaunched() {
265 VLOG(1) << "\n\nExtensionProcess was started!";
268 void XWalkExtensionProcessHost::OnRenderChannelCreated(
269 const IPC::ChannelHandle& handle) {
270 is_extension_process_channel_ready_ = true;
271 ep_rp_channel_handle_ = handle;
272 ReplyChannelHandleToRenderProcess();
274 delegate_->OnRenderChannelCreated(render_process_host_->GetID());
277 void XWalkExtensionProcessHost::ReplyChannelHandleToRenderProcess() {
278 // Replying the channel handle to RP depends on two events:
279 // - EP already notified EPH that new channel was created (for RP<->EP).
280 // - RP already asked for the channel handle.
282 // The order for this events is not determined, so we call this function from
283 // both, and the second execution will send the reply.
284 if (!is_extension_process_channel_ready_
285 || !pending_reply_for_render_process_)
288 XWalkExtensionProcessHostMsg_GetExtensionProcessChannel::WriteReplyParams(
289 pending_reply_for_render_process_.get(), ep_rp_channel_handle_);
291 render_process_host_->Send(pending_reply_for_render_process_.release());
294 void XWalkExtensionProcessHost::ReplyAccessControlToExtension(
295 IPC::Message* reply_msg,
296 RuntimePermission perm) {
297 XWalkExtensionProcessHostMsg_CheckAPIAccessControl
298 ::WriteReplyParams(reply_msg, perm);
302 void XWalkExtensionProcessHost::OnCheckAPIAccessControl(
303 const std::string& extension_name,
304 const std::string& api_name, IPC::Message* reply_msg) {
306 delegate_->OnCheckAPIAccessControl(render_process_host_->GetID(),
307 extension_name, api_name,
308 base::Bind(&XWalkExtensionProcessHost::ReplyAccessControlToExtension,
309 base::Unretained(this),
313 void XWalkExtensionProcessHost::OnRegisterPermissions(
314 const std::string& extension_name,
315 const std::string& perm_table, bool* result) {
317 *result = delegate_->OnRegisterPermissions(
318 render_process_host_->GetID(), extension_name, perm_table);
321 bool XWalkExtensionProcessHost::Send(IPC::Message* msg) {
323 return process_->GetHost()->Send(msg);
325 return channel_->Send(msg);
329 } // namespace extensions