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 "xwalk/extensions/common/xwalk_extension_messages.h"
22 #include "xwalk/extensions/common/xwalk_extension_switches.h"
23 #include "xwalk/runtime/common/xwalk_switches.h"
25 using content::BrowserThread;
28 namespace extensions {
30 // This filter is used by ExtensionProcessHost to intercept when Render Process
31 // ask for the Extension Channel handle (that is created by extension process).
32 class XWalkExtensionProcessHost::RenderProcessMessageFilter
33 : public IPC::ChannelProxy::MessageFilter {
35 explicit RenderProcessMessageFilter(XWalkExtensionProcessHost* eph)
38 // This exists to fulfill the requirement for delayed reply handling, since it
39 // needs to send a message back if the parameters couldn't be correctly read
40 // from the original message received. See DispatchDealyReplyWithSendParams().
41 bool Send(IPC::Message* message) {
43 return eph_->render_process_host_->Send(message);
53 // IPC::ChannelProxy::MessageFilter implementation.
54 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
56 IPC_BEGIN_MESSAGE_MAP(RenderProcessMessageFilter, message)
57 IPC_MESSAGE_HANDLER_DELAY_REPLY(
58 XWalkExtensionProcessHostMsg_GetExtensionProcessChannel,
59 OnGetExtensionProcessChannel)
60 IPC_MESSAGE_UNHANDLED(handled = false)
65 void OnGetExtensionProcessChannel(IPC::Message* reply) {
66 scoped_ptr<IPC::Message> scoped_reply(reply);
68 eph_->OnGetExtensionProcessChannel(scoped_reply.Pass());
71 virtual ~RenderProcessMessageFilter() {}
73 XWalkExtensionProcessHost* eph_;
76 class ExtensionSandboxedProcessLauncherDelegate
77 : public content::SandboxedProcessLauncherDelegate {
79 explicit ExtensionSandboxedProcessLauncherDelegate(
80 content::ChildProcessHost* host)
82 : ipc_fd_(host->TakeClientFileDescriptor()) {}
84 virtual ~ExtensionSandboxedProcessLauncherDelegate() {}
87 virtual void ShouldSandbox(bool* in_sandbox) OVERRIDE {
90 #elif defined(OS_POSIX)
91 virtual int GetIpcFd() OVERRIDE {
101 DISALLOW_COPY_AND_ASSIGN(ExtensionSandboxedProcessLauncherDelegate);
104 bool XWalkExtensionProcessHost::Delegate::OnRegisterPermissions(
105 int render_process_id,
106 const std::string& extension_name,
107 const std::string& perm_table) {
111 XWalkExtensionProcessHost::XWalkExtensionProcessHost(
112 content::RenderProcessHost* render_process_host,
113 const base::FilePath& external_extensions_path,
114 XWalkExtensionProcessHost::Delegate* delegate,
115 const base::ValueMap& runtime_variables)
116 : ep_rp_channel_handle_(""),
117 render_process_host_(render_process_host),
118 render_process_message_filter_(new RenderProcessMessageFilter(this)),
119 external_extensions_path_(external_extensions_path),
120 is_extension_process_channel_ready_(false),
122 runtime_variables_(runtime_variables) {
123 render_process_host_->GetChannel()->AddFilter(render_process_message_filter_);
124 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
125 base::Bind(&XWalkExtensionProcessHost::StartProcess,
126 base::Unretained(this)));
129 XWalkExtensionProcessHost::~XWalkExtensionProcessHost() {
130 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
131 render_process_message_filter_->Invalidate();
137 void ToListValue(base::ValueMap* vm, base::ListValue* lv) {
140 for (base::ValueMap::iterator it = vm->begin(); it != vm->end(); it++) {
141 base::DictionaryValue* dv = new base::DictionaryValue();
142 dv->Set(it->first, it->second);
149 void XWalkExtensionProcessHost::StartProcess() {
150 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
151 CHECK(!process_ || !channel_);
153 CommandLine* cmd_line = CommandLine::ForCurrentProcess();
154 if (cmd_line->HasSwitch(switches::kXWalkRunAsService)) {
155 #if defined(OS_LINUX)
156 std::string channel_id =
157 IPC::Channel::GenerateVerifiedChannelID(std::string());
158 channel_.reset(new IPC::Channel(
159 channel_id, IPC::Channel::MODE_SERVER, this));
160 if (!channel_->Connect())
162 IPC::ChannelHandle channel_handle(channel_id,
163 base::FileDescriptor(channel_->TakeClientFileDescriptor(), true));
164 BrowserThread::PostTask(
165 BrowserThread::UI, FROM_HERE,
167 &XWalkExtensionProcessHost::Delegate::OnExtensionProcessCreated,
168 base::Unretained(delegate_), render_process_host_->GetID(),
174 process_.reset(content::BrowserChildProcessHost::Create(
175 content::PROCESS_TYPE_CONTENT_END, this));
177 std::string channel_id = process_->GetHost()->CreateChannel();
178 CHECK(!channel_id.empty());
180 CommandLine::StringType extension_cmd_prefix;
181 #if defined(OS_POSIX)
182 const CommandLine &browser_command_line = *CommandLine::ForCurrentProcess();
183 extension_cmd_prefix = browser_command_line.GetSwitchValueNative(
184 switches::kXWalkExtensionCmdPrefix);
187 #if defined(OS_LINUX)
188 int flags = extension_cmd_prefix.empty() ?
189 content::ChildProcessHost::CHILD_ALLOW_SELF :
190 content::ChildProcessHost::CHILD_NORMAL;
192 int flags = content::ChildProcessHost::CHILD_NORMAL;
195 base::FilePath exe_path = content::ChildProcessHost::GetChildPath(flags);
196 if (exe_path.empty())
199 scoped_ptr<CommandLine> cmd_line(new CommandLine(exe_path));
200 cmd_line->AppendSwitchASCII(switches::kProcessType,
201 switches::kXWalkExtensionProcess);
202 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
203 if (!extension_cmd_prefix.empty())
204 cmd_line->PrependWrapper(extension_cmd_prefix);
207 new ExtensionSandboxedProcessLauncherDelegate(process_->GetHost()),
211 base::ListValue runtime_variables_lv;
212 ToListValue(&const_cast<base::ValueMap&>(runtime_variables_),
213 &runtime_variables_lv);
214 Send(new XWalkExtensionProcessMsg_RegisterExtensions(
215 external_extensions_path_, runtime_variables_lv));
218 void XWalkExtensionProcessHost::StopProcess() {
225 void XWalkExtensionProcessHost::OnGetExtensionProcessChannel(
226 scoped_ptr<IPC::Message> reply) {
227 pending_reply_for_render_process_ = reply.Pass();
228 ReplyChannelHandleToRenderProcess();
231 bool XWalkExtensionProcessHost::OnMessageReceived(const IPC::Message& message) {
233 IPC_BEGIN_MESSAGE_MAP(XWalkExtensionProcessHost, message)
235 XWalkExtensionProcessHostMsg_RenderProcessChannelCreated,
236 OnRenderChannelCreated)
237 IPC_MESSAGE_HANDLER_DELAY_REPLY(
238 XWalkExtensionProcessHostMsg_CheckAPIAccessControl,
239 OnCheckAPIAccessControl)
241 XWalkExtensionProcessHostMsg_RegisterPermissions,
242 OnRegisterPermissions)
243 IPC_MESSAGE_UNHANDLED(handled = false)
244 IPC_END_MESSAGE_MAP()
248 void XWalkExtensionProcessHost::OnChannelError() {
249 // This function is called just before
250 // BrowserChildProcessHostImpl::OnChildDisconnected gets called. Please refer
251 // to ChildProcessHostImpl::OnChannelError() from child_process_host_impl.cc.
252 // This means that content::BrowserChildProcessHost (process_, in our case)
253 // is about to delete its delegate, which is us!
254 // We should alert our XWalkExtensionProcessHost::Delegate, since it will
255 // most likely have a pointer to us that needs to be invalidated.
257 VLOG(1) << "\n\nExtensionProcess crashed";
259 delegate_->OnExtensionProcessDied(this, render_process_host_->GetID());
262 void XWalkExtensionProcessHost::OnProcessLaunched() {
263 VLOG(1) << "\n\nExtensionProcess was started!";
266 void XWalkExtensionProcessHost::OnRenderChannelCreated(
267 const IPC::ChannelHandle& handle) {
268 is_extension_process_channel_ready_ = true;
269 ep_rp_channel_handle_ = handle;
270 ReplyChannelHandleToRenderProcess();
273 void XWalkExtensionProcessHost::ReplyChannelHandleToRenderProcess() {
274 // Replying the channel handle to RP depends on two events:
275 // - EP already notified EPH that new channel was created (for RP<->EP).
276 // - RP already asked for the channel handle.
278 // The order for this events is not determined, so we call this function from
279 // both, and the second execution will send the reply.
280 if (!is_extension_process_channel_ready_
281 || !pending_reply_for_render_process_)
284 XWalkExtensionProcessHostMsg_GetExtensionProcessChannel::WriteReplyParams(
285 pending_reply_for_render_process_.get(), ep_rp_channel_handle_);
287 render_process_host_->Send(pending_reply_for_render_process_.release());
290 void XWalkExtensionProcessHost::ReplyAccessControlToExtension(
291 IPC::Message* reply_msg,
292 RuntimePermission perm) {
293 XWalkExtensionProcessHostMsg_CheckAPIAccessControl
294 ::WriteReplyParams(reply_msg, perm);
298 void XWalkExtensionProcessHost::OnCheckAPIAccessControl(
299 const std::string& extension_name,
300 const std::string& api_name, IPC::Message* reply_msg) {
302 delegate_->OnCheckAPIAccessControl(render_process_host_->GetID(),
303 extension_name, api_name,
304 base::Bind(&XWalkExtensionProcessHost::ReplyAccessControlToExtension,
305 base::Unretained(this),
309 void XWalkExtensionProcessHost::OnRegisterPermissions(
310 const std::string& extension_name,
311 const std::string& perm_table, bool* result) {
313 *result = delegate_->OnRegisterPermissions(
314 render_process_host_->GetID(), extension_name, perm_table);
317 bool XWalkExtensionProcessHost::Send(IPC::Message* msg) {
319 return process_->GetHost()->Send(msg);
321 return channel_->Send(msg);
325 } // namespace extensions