Upstream version 5.34.97.0
[platform/framework/web/crosswalk.git] / src / xwalk / extensions / browser / xwalk_extension_process_host.cc
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.
4
5 #include "xwalk/extensions/browser/xwalk_extension_process_host.h"
6
7 #include <string>
8
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 #if defined(OS_WIN)
19 #include "content/public/common/sandboxed_process_launcher_delegate.h"
20 #endif
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"
25
26 using content::BrowserThread;
27
28 namespace xwalk {
29 namespace extensions {
30
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 {
35  public:
36   explicit RenderProcessMessageFilter(XWalkExtensionProcessHost* eph)
37       : eph_(eph) {}
38
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) {
43     if (eph_)
44       return eph_->render_process_host_->Send(message);
45     delete message;
46     return false;
47   }
48
49   void Invalidate() {
50     eph_ = NULL;
51   }
52
53  private:
54   // IPC::ChannelProxy::MessageFilter implementation.
55   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
56     bool handled = true;
57     IPC_BEGIN_MESSAGE_MAP(RenderProcessMessageFilter, message)
58       IPC_MESSAGE_HANDLER_DELAY_REPLY(
59           XWalkExtensionProcessHostMsg_GetExtensionProcessChannel,
60           OnGetExtensionProcessChannel)
61       IPC_MESSAGE_UNHANDLED(handled = false)
62     IPC_END_MESSAGE_MAP()
63     return handled;
64   }
65
66   void OnGetExtensionProcessChannel(IPC::Message* reply) {
67     scoped_ptr<IPC::Message> scoped_reply(reply);
68     if (eph_)
69       eph_->OnGetExtensionProcessChannel(scoped_reply.Pass());
70   }
71
72   virtual ~RenderProcessMessageFilter() {}
73
74   XWalkExtensionProcessHost* eph_;
75 };
76
77 #if defined(OS_WIN)
78 class ExtensionSandboxedProcessLauncherDelegate
79     : public content::SandboxedProcessLauncherDelegate {
80  public:
81   ExtensionSandboxedProcessLauncherDelegate() {}
82   virtual ~ExtensionSandboxedProcessLauncherDelegate() {}
83
84   virtual void ShouldSandbox(bool* in_sandbox) OVERRIDE {
85     *in_sandbox = false;
86   }
87
88  private:
89   DISALLOW_COPY_AND_ASSIGN(ExtensionSandboxedProcessLauncherDelegate);
90 };
91 #endif
92
93 bool XWalkExtensionProcessHost::Delegate::OnRegisterPermissions(
94     int render_process_id,
95     const std::string& extension_name,
96     const std::string& perm_table) {
97   return false;
98 }
99
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),
110       delegate_(delegate),
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)));
116 }
117
118 XWalkExtensionProcessHost::~XWalkExtensionProcessHost() {
119   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
120   render_process_message_filter_->Invalidate();
121   StopProcess();
122 }
123
124 namespace {
125
126 void ToListValue(base::ValueMap* vm, base::ListValue* lv) {
127   lv->Clear();
128
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);
132     lv->Append(dv);
133   }
134 }
135
136 }  // namespace
137
138 void XWalkExtensionProcessHost::StartProcess() {
139   CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
140   CHECK(!process_);
141
142   process_.reset(content::BrowserChildProcessHost::Create(
143       content::PROCESS_TYPE_CONTENT_END, this));
144
145   std::string channel_id = process_->GetHost()->CreateChannel();
146   CHECK(!channel_id.empty());
147
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);
154   process_->Launch(
155 #if defined(OS_WIN)
156       new ExtensionSandboxedProcessLauncherDelegate(),
157 #elif defined(OS_POSIX)
158     false, base::EnvironmentMap(),
159 #endif
160     cmd_line.release());
161
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));
167 }
168
169 void XWalkExtensionProcessHost::StopProcess() {
170   DCHECK(process_);
171   process_.reset();
172 }
173
174 void XWalkExtensionProcessHost::OnGetExtensionProcessChannel(
175     scoped_ptr<IPC::Message> reply) {
176   pending_reply_for_render_process_ = reply.Pass();
177   ReplyChannelHandleToRenderProcess();
178 }
179
180 bool XWalkExtensionProcessHost::OnMessageReceived(const IPC::Message& message) {
181   bool handled = true;
182   IPC_BEGIN_MESSAGE_MAP(XWalkExtensionProcessHost, message)
183     IPC_MESSAGE_HANDLER(
184         XWalkExtensionProcessHostMsg_RenderProcessChannelCreated,
185         OnRenderChannelCreated)
186     IPC_MESSAGE_HANDLER_DELAY_REPLY(
187         XWalkExtensionProcessHostMsg_CheckAPIAccessControl,
188         OnCheckAPIAccessControl)
189     IPC_MESSAGE_HANDLER(
190         XWalkExtensionProcessHostMsg_RegisterPermissions,
191         OnRegisterPermissions)
192     IPC_MESSAGE_UNHANDLED(handled = false)
193   IPC_END_MESSAGE_MAP()
194   return handled;
195 }
196
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.
205
206   VLOG(1) << "\n\nExtensionProcess crashed";
207   if (delegate_)
208     delegate_->OnExtensionProcessDied(this, render_process_host_->GetID());
209 }
210
211 void XWalkExtensionProcessHost::OnProcessLaunched() {
212   VLOG(1) << "\n\nExtensionProcess was started!";
213 }
214
215 void XWalkExtensionProcessHost::OnRenderChannelCreated(
216     const IPC::ChannelHandle& handle) {
217   is_extension_process_channel_ready_ = true;
218   ep_rp_channel_handle_ = handle;
219   ReplyChannelHandleToRenderProcess();
220 }
221
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.
226   //
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_)
231     return;
232
233   XWalkExtensionProcessHostMsg_GetExtensionProcessChannel::WriteReplyParams(
234       pending_reply_for_render_process_.get(), ep_rp_channel_handle_);
235
236   render_process_host_->Send(pending_reply_for_render_process_.release());
237 }
238
239 void XWalkExtensionProcessHost::ReplyAccessControlToExtension(
240     IPC::Message* reply_msg,
241     RuntimePermission perm) {
242   XWalkExtensionProcessHostMsg_CheckAPIAccessControl
243       ::WriteReplyParams(reply_msg, perm);
244   Send(reply_msg);
245 }
246
247 void XWalkExtensionProcessHost::OnCheckAPIAccessControl(
248     const std::string& extension_name,
249     const std::string& api_name, IPC::Message* reply_msg) {
250   CHECK(delegate_);
251   delegate_->OnCheckAPIAccessControl(render_process_host_->GetID(),
252                                      extension_name, api_name,
253       base::Bind(&XWalkExtensionProcessHost::ReplyAccessControlToExtension,
254                  base::Unretained(this),
255                  reply_msg));
256 }
257
258 void XWalkExtensionProcessHost::OnRegisterPermissions(
259     const std::string& extension_name,
260     const std::string& perm_table, bool* result) {
261   CHECK(delegate_);
262   *result = delegate_->OnRegisterPermissions(
263       render_process_host_->GetID(), extension_name, perm_table);
264 }
265
266 bool XWalkExtensionProcessHost::Send(IPC::Message* msg) {
267   return process_->GetHost()->Send(msg);
268 }
269
270 }  // namespace extensions
271 }  // namespace xwalk
272