2437f4825f6f9cb704df520247443566879a6b97
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / linux / running_application_object.cc
1 // Copyright (c) 2013 Intel Corporation. All rights reserved.
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "xwalk/application/browser/linux/running_application_object.h"
7
8 #include <string>
9 #include "base/values.h"
10 #include "base/bind.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "dbus/bus.h"
13 #include "dbus/message.h"
14 #include "dbus/exported_object.h"
15 #include "xwalk/application/browser/application_tizen.h"
16 #include "xwalk/application/browser/linux/running_applications_manager.h"
17
18 namespace {
19
20 // D-Bus Interface implemented by objects that represent running
21 // applications.
22 //
23 // Methods:
24 //
25 //   Terminate()
26 //     Will terminate the running application. This object will be unregistered
27 //     from D-Bus.
28 //
29 // Properties:
30 //
31 //   readonly string AppID
32 const char kRunningApplicationDBusInterface[] =
33     "org.crosswalkproject.Running.Application1";
34
35 const char kRunningApplicationDBusError[] =
36     "org.crosswalkproject.Running.Application.Error";
37
38
39 }  // namespace
40
41 namespace xwalk {
42 namespace application {
43
44 RunningApplicationObject::RunningApplicationObject(
45     scoped_refptr<dbus::Bus> bus,
46     const std::string& app_id,
47     const std::string& launcher_name,
48     Application* application)
49     : dbus::ManagedObject(bus, GetRunningPathForAppID(app_id)),
50       bus_(bus),
51       launcher_name_(launcher_name),
52       application_(application) {
53   ListenForOwnerChange();
54
55   properties()->Set(
56       kRunningApplicationDBusInterface, "AppID",
57       scoped_ptr<base::Value>(new base::StringValue(app_id)));
58
59   // FIXME: RemoveAllCookies and SetUserAgentString
60   // are exported for web_setting extension usage.
61   // This is a temporary solution - when another
62   // IPC on extension process side is implemented,
63   // these methods have to be removed.
64   dbus_object()->ExportMethod(
65       kRunningApplicationDBusInterface, "RemoveAllCookies",
66       base::Bind(&RunningApplicationObject::OnRemoveAllCookies,
67                  base::Unretained(this)),
68       base::Bind(&RunningApplicationObject::OnExported,
69                  base::Unretained(this)));
70
71   dbus_object()->ExportMethod(
72       kRunningApplicationDBusInterface, "SetUserAgentString",
73       base::Bind(&RunningApplicationObject::OnSetUserAgentString,
74                  base::Unretained(this)),
75       base::Bind(&RunningApplicationObject::OnExported,
76                  base::Unretained(this)));
77
78   dbus_object()->ExportMethod(
79       kRunningApplicationDBusInterface, "Terminate",
80       base::Bind(&RunningApplicationObject::OnTerminate,
81                  base::Unretained(this)),
82       base::Bind(&RunningApplicationObject::OnExported,
83                  base::Unretained(this)));
84
85   dbus_object()->ExportMethod(
86       kRunningApplicationDBusInterface, "GetEPChannel",
87       base::Bind(&RunningApplicationObject::OnGetExtensionProcessChannel,
88                  base::Unretained(this)),
89       base::Bind(&RunningApplicationObject::OnExported,
90                  base::Unretained(this)));
91
92 #if defined(OS_TIZEN)
93   dbus_object()->ExportMethod(
94       kRunningApplicationDBusInterface, "Hide",
95       base::Bind(&RunningApplicationObject::OnHide,
96                  base::Unretained(this)),
97       base::Bind(&RunningApplicationObject::OnExported,
98                  base::Unretained(this)));
99
100   dbus_object()->ExportMethod(
101       kRunningApplicationDBusInterface, "Suspend",
102       base::Bind(&RunningApplicationObject::OnSuspend,
103                  base::Unretained(this)),
104       base::Bind(&RunningApplicationObject::OnExported,
105                  base::Unretained(this)));
106
107   dbus_object()->ExportMethod(
108       kRunningApplicationDBusInterface, "Resume",
109       base::Bind(&RunningApplicationObject::OnResume,
110                  base::Unretained(this)),
111       base::Bind(&RunningApplicationObject::OnExported,
112                  base::Unretained(this)));
113 #endif
114 }
115
116 RunningApplicationObject::~RunningApplicationObject() {
117   UnlistenForOwnerChange();
118 }
119
120 void RunningApplicationObject::TerminateApplication() {
121   application_->Terminate();
122 }
123
124 void RunningApplicationObject::OnExported(const std::string& interface_name,
125                                           const std::string& method_name,
126                                           bool success) {
127   if (!success) {
128     LOG(WARNING) << "Error exporting method '" << interface_name
129                  << "." << method_name << "' in '"
130                  << path().value() << "'.";
131   }
132 }
133
134 void RunningApplicationObject::SetUserAgentStringOnIOThread(
135     const std::string& user_agent_string) {
136   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
137   ToApplicationTizen(application_)->SetUserAgentString(user_agent_string);
138 }
139
140 void RunningApplicationObject::OnRemoveAllCookies(dbus::MethodCall* method_call,
141     dbus::ExportedObject::ResponseSender response_sender) {
142   if (method_call->GetSender() != launcher_name_) {
143     scoped_ptr<dbus::ErrorResponse> error_response =
144         dbus::ErrorResponse::FromMethodCall(method_call,
145                                             kRunningApplicationDBusError,
146                                             "Not permitted");
147     response_sender.Run(error_response.PassAs<dbus::Response>());
148     return;
149   }
150
151   ToApplicationTizen(application_)->RemoveAllCookies();
152
153   scoped_ptr<dbus::Response> response =
154       dbus::Response::FromMethodCall(method_call);
155   response_sender.Run(response.Pass());
156 }
157
158 void RunningApplicationObject::OnSetUserAgentString(
159     dbus::MethodCall* method_call,
160     dbus::ExportedObject::ResponseSender response_sender) {
161   if (method_call->GetSender() != launcher_name_) {
162     scoped_ptr<dbus::ErrorResponse> error_response =
163         dbus::ErrorResponse::FromMethodCall(method_call,
164                                             kRunningApplicationDBusError,
165                                             "Not permitted");
166     response_sender.Run(error_response.PassAs<dbus::Response>());
167     return;
168   }
169   dbus::MessageReader reader(method_call);
170   std::string new_user_agent;
171   if (reader.PopString(&new_user_agent)) {
172     content::BrowserThread::PostTask(
173         content::BrowserThread::IO, FROM_HERE,
174         base::Bind(&RunningApplicationObject::SetUserAgentStringOnIOThread,
175                    base::Unretained(this), new_user_agent));
176     scoped_ptr<dbus::Response> response =
177         dbus::Response::FromMethodCall(method_call);
178     response_sender.Run(response.Pass());
179   } else {
180     scoped_ptr<dbus::ErrorResponse> error_response =
181         dbus::ErrorResponse::FromMethodCall(method_call,
182                                             kRunningApplicationDBusError,
183                                             "Wrong user agent string");
184     response_sender.Run(error_response.PassAs<dbus::Response>());
185   }
186 }
187
188 void RunningApplicationObject::OnTerminate(
189     dbus::MethodCall* method_call,
190     dbus::ExportedObject::ResponseSender response_sender) {
191   // We only allow the caller of Launch() to call Terminate().
192   if (method_call->GetSender() != launcher_name_) {
193     scoped_ptr<dbus::ErrorResponse> error_response =
194         dbus::ErrorResponse::FromMethodCall(method_call,
195                                             kRunningApplicationDBusError,
196                                             "Not permitted");
197     response_sender.Run(error_response.PassAs<dbus::Response>());
198     return;
199   }
200
201   TerminateApplication();
202
203   scoped_ptr<dbus::Response> response =
204       dbus::Response::FromMethodCall(method_call);
205   response_sender.Run(response.Pass());
206 }
207
208 void RunningApplicationObject::OnGetExtensionProcessChannel(
209     dbus::MethodCall* method_call,
210     dbus::ExportedObject::ResponseSender response_sender) {
211   content::BrowserThread::PostTask(
212       content::BrowserThread::FILE,
213       FROM_HERE,
214       base::Bind(&RunningApplicationObject::SendChannel,
215                  base::Unretained(this),
216                  method_call,
217                  response_sender));
218 }
219
220 #if defined(OS_TIZEN)
221 void RunningApplicationObject::OnHide(
222     dbus::MethodCall* method_call,
223     dbus::ExportedObject::ResponseSender response_sender) {
224   if (method_call->GetSender() != launcher_name_) {
225     scoped_ptr<dbus::ErrorResponse> error_response =
226         dbus::ErrorResponse::FromMethodCall(method_call,
227                                             kRunningApplicationDBusError,
228                                             "Not permitted");
229     response_sender.Run(error_response.PassAs<dbus::Response>());
230     return;
231   }
232
233   ToApplicationTizen(application_)->Hide();
234
235   scoped_ptr<dbus::Response> response =
236       dbus::Response::FromMethodCall(method_call);
237   response_sender.Run(response.Pass());
238 }
239
240 void RunningApplicationObject::OnSuspend(
241     dbus::MethodCall* method_call,
242     dbus::ExportedObject::ResponseSender response_sender) {
243   if (method_call->GetSender() != launcher_name_) {
244     scoped_ptr<dbus::ErrorResponse> error_response =
245         dbus::ErrorResponse::FromMethodCall(method_call,
246                                             kRunningApplicationDBusError,
247                                             "Not permitted");
248     response_sender.Run(error_response.PassAs<dbus::Response>());
249     return;
250   }
251
252   ToApplicationTizen(application_)->Suspend();
253
254   scoped_ptr<dbus::Response> response =
255       dbus::Response::FromMethodCall(method_call);
256   response_sender.Run(response.Pass());
257 }
258
259 void RunningApplicationObject::OnResume(
260     dbus::MethodCall* method_call,
261     dbus::ExportedObject::ResponseSender response_sender) {
262   if (method_call->GetSender() != launcher_name_) {
263     scoped_ptr<dbus::ErrorResponse> error_response =
264         dbus::ErrorResponse::FromMethodCall(method_call,
265                                             kRunningApplicationDBusError,
266                                             "Not permitted");
267     response_sender.Run(error_response.PassAs<dbus::Response>());
268     return;
269   }
270
271   ToApplicationTizen(application_)->Resume();
272
273   scoped_ptr<dbus::Response> response =
274       dbus::Response::FromMethodCall(method_call);
275   response_sender.Run(response.Pass());
276 }
277 #endif
278
279 void RunningApplicationObject::ListenForOwnerChange() {
280   owner_change_callback_ =
281       base::Bind(&RunningApplicationObject::OnNameOwnerChanged,
282                  base::Unretained(this));
283   bus_->ListenForServiceOwnerChange(launcher_name_, owner_change_callback_);
284 }
285
286 void RunningApplicationObject::UnlistenForOwnerChange() {
287   if (owner_change_callback_.is_null())
288     return;
289   bus_->UnlistenForServiceOwnerChange(launcher_name_, owner_change_callback_);
290   owner_change_callback_.Reset();
291 }
292
293 void RunningApplicationObject::OnNameOwnerChanged(
294     const std::string& service_owner) {
295   if (service_owner.empty()) {
296     // The process that sent the 'Launch' message has exited the session bus,
297     // we should kill the Running Application.
298     OnLauncherDisappeared();
299   }
300 }
301
302 void RunningApplicationObject::OnLauncherDisappeared() {
303   TerminateApplication();
304 }
305
306 void RunningApplicationObject::SendChannel(
307     dbus::MethodCall* method_call,
308     dbus::ExportedObject::ResponseSender response_sender) {
309   scoped_ptr<dbus::Response> response =
310       dbus::Response::FromMethodCall(method_call);
311
312   int fd = ep_bp_channel_.socket.fd;
313   if (fd == -1) {  // EP was not yet created, return empty response.
314     response_sender.Run(response.Pass());
315     return;
316   }
317
318   dbus::MessageWriter writer(response.get());
319   writer.AppendString(ep_bp_channel_.name);
320
321   scoped_ptr<dbus::FileDescriptor> client_fd(new dbus::FileDescriptor(fd));
322   client_fd->CheckValidity();
323   CHECK(client_fd->is_valid());
324   writer.AppendFileDescriptor(*client_fd);
325
326   response_sender.Run(response.Pass());
327 }
328
329 void RunningApplicationObject::ExtensionProcessCreated(
330     const IPC::ChannelHandle& handle) {
331   ep_bp_channel_ = handle;
332   dbus::Signal signal(kRunningApplicationDBusInterface, "EPChannelCreated");
333   dbus_object()->SendSignal(&signal);
334 }
335
336 }  // namespace application
337 }  // namespace xwalk