8c49e1a4cb446fe8082d3e02697414657882f26c
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / linux / running_application_object.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/application/browser/linux/running_application_object.h"
6
7 #include <string>
8 #include "base/values.h"
9 #include "base/bind.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "dbus/bus.h"
12 #include "dbus/message.h"
13 #include "dbus/exported_object.h"
14 #include "xwalk/application/browser/application_tizen.h"
15 #include "xwalk/application/browser/linux/running_applications_manager.h"
16
17 namespace {
18
19 // D-Bus Interface implemented by objects that represent running
20 // applications.
21 //
22 // Methods:
23 //
24 //   Terminate()
25 //     Will terminate the running application. This object will be unregistered
26 //     from D-Bus.
27 //
28 // Properties:
29 //
30 //   readonly string AppID
31 const char kRunningApplicationDBusInterface[] =
32     "org.crosswalkproject.Running.Application1";
33
34 const char kRunningApplicationDBusError[] =
35     "org.crosswalkproject.Running.Application.Error";
36
37
38 }  // namespace
39
40 namespace xwalk {
41 namespace application {
42
43 RunningApplicationObject::RunningApplicationObject(
44     scoped_refptr<dbus::Bus> bus,
45     const std::string& app_id,
46     const std::string& launcher_name,
47     Application* application)
48     : dbus::ManagedObject(bus, GetRunningPathForAppID(app_id)),
49       bus_(bus),
50       launcher_name_(launcher_name),
51       application_(application) {
52   ListenForOwnerChange();
53
54   properties()->Set(
55       kRunningApplicationDBusInterface, "AppID",
56       scoped_ptr<base::Value>(base::Value::CreateStringValue(app_id)));
57
58   dbus_object()->ExportMethod(
59       kRunningApplicationDBusInterface, "Terminate",
60       base::Bind(&RunningApplicationObject::OnTerminate,
61                  base::Unretained(this), Application::Normal),
62       base::Bind(&RunningApplicationObject::OnExported,
63                  base::Unretained(this)));
64
65   dbus_object()->ExportMethod(
66       kRunningApplicationDBusInterface, "ForceTerminate",
67       base::Bind(&RunningApplicationObject::OnTerminate,
68                  base::Unretained(this), Application::Immediate),
69       base::Bind(&RunningApplicationObject::OnExported,
70                  base::Unretained(this)));
71
72   dbus_object()->ExportMethod(
73       kRunningApplicationDBusInterface, "GetEPChannel",
74       base::Bind(&RunningApplicationObject::OnGetExtensionProcessChannel,
75                  base::Unretained(this)),
76       base::Bind(&RunningApplicationObject::OnExported,
77                  base::Unretained(this)));
78
79 #if defined(OS_TIZEN)
80   dbus_object()->ExportMethod(
81       kRunningApplicationDBusInterface, "Hide",
82       base::Bind(&RunningApplicationObject::OnHide,
83                  base::Unretained(this)),
84       base::Bind(&RunningApplicationObject::OnExported,
85                  base::Unretained(this)));
86 #endif
87 }
88
89 RunningApplicationObject::~RunningApplicationObject() {
90   UnlistenForOwnerChange();
91 }
92
93 void RunningApplicationObject::TerminateApplication(
94     Application::TerminationMode mode) {
95   // The application might be still running after 'Terminate' call
96   // (if 'mode == Normal' and it contains 'OnSuspend' handlers),
97   // so we do not call 'UnlistenForOwnerChange' here - it will
98   // be called anyway right before the actual 'Application' instance
99   // deletion.
100   application_->Terminate(mode);
101 }
102
103 void RunningApplicationObject::OnExported(const std::string& interface_name,
104                                           const std::string& method_name,
105                                           bool success) {
106   if (!success) {
107     LOG(WARNING) << "Error exporting method '" << interface_name
108                  << "." << method_name << "' in '"
109                  << path().value() << "'.";
110   }
111 }
112
113 void RunningApplicationObject::OnTerminate(
114     Application::TerminationMode mode,
115     dbus::MethodCall* method_call,
116     dbus::ExportedObject::ResponseSender response_sender) {
117   // We only allow the caller of Launch() to call Terminate().
118   if (method_call->GetSender() != launcher_name_) {
119     scoped_ptr<dbus::ErrorResponse> error_response =
120         dbus::ErrorResponse::FromMethodCall(method_call,
121                                             kRunningApplicationDBusError,
122                                             "Not permitted");
123     response_sender.Run(error_response.PassAs<dbus::Response>());
124     return;
125   }
126
127   TerminateApplication(mode);
128
129   scoped_ptr<dbus::Response> response =
130       dbus::Response::FromMethodCall(method_call);
131   response_sender.Run(response.Pass());
132 }
133
134 void RunningApplicationObject::OnGetExtensionProcessChannel(
135     dbus::MethodCall* method_call,
136     dbus::ExportedObject::ResponseSender response_sender) {
137   content::BrowserThread::PostTask(
138       content::BrowserThread::FILE,
139       FROM_HERE,
140       base::Bind(&RunningApplicationObject::SendChannel,
141                  base::Unretained(this),
142                  method_call,
143                  response_sender));
144 }
145
146 #if defined(OS_TIZEN)
147 void RunningApplicationObject::OnHide(
148     dbus::MethodCall* method_call,
149     dbus::ExportedObject::ResponseSender response_sender) {
150   if (method_call->GetSender() != launcher_name_) {
151     scoped_ptr<dbus::ErrorResponse> error_response =
152         dbus::ErrorResponse::FromMethodCall(method_call,
153                                             kRunningApplicationDBusError,
154                                             "Not permitted");
155     response_sender.Run(error_response.PassAs<dbus::Response>());
156     return;
157   }
158
159   ToApplicationTizen(application_)->Hide();
160
161   scoped_ptr<dbus::Response> response =
162       dbus::Response::FromMethodCall(method_call);
163   response_sender.Run(response.Pass());
164 }
165 #endif
166
167 void RunningApplicationObject::ListenForOwnerChange() {
168   owner_change_callback_ =
169       base::Bind(&RunningApplicationObject::OnNameOwnerChanged,
170                  base::Unretained(this));
171   bus_->ListenForServiceOwnerChange(launcher_name_, owner_change_callback_);
172 }
173
174 void RunningApplicationObject::UnlistenForOwnerChange() {
175   if (owner_change_callback_.is_null())
176     return;
177   bus_->UnlistenForServiceOwnerChange(launcher_name_, owner_change_callback_);
178   owner_change_callback_.Reset();
179 }
180
181 void RunningApplicationObject::OnNameOwnerChanged(
182     const std::string& service_owner) {
183   if (service_owner.empty()) {
184     // The process that sent the 'Launch' message has exited the session bus,
185     // we should kill the Running Application.
186     OnLauncherDisappeared();
187   }
188 }
189
190 void RunningApplicationObject::OnLauncherDisappeared() {
191   // Do not care about 'OnSuspend' handlers if the launcher is already killed.
192   TerminateApplication(Application::Immediate);
193 }
194
195 void RunningApplicationObject::SendChannel(
196     dbus::MethodCall* method_call,
197     dbus::ExportedObject::ResponseSender response_sender) {
198   scoped_ptr<dbus::Response> response =
199       dbus::Response::FromMethodCall(method_call);
200
201   int fd = ep_bp_channel_.socket.fd;
202   if (fd == -1) {  // EP was not yet created, return empty response.
203     response_sender.Run(response.Pass());
204     return;
205   }
206
207   dbus::MessageWriter writer(response.get());
208   writer.AppendString(ep_bp_channel_.name);
209
210   scoped_ptr<dbus::FileDescriptor> client_fd(new dbus::FileDescriptor(fd));
211   client_fd->CheckValidity();
212   CHECK(client_fd->is_valid());
213   writer.AppendFileDescriptor(*client_fd);
214
215   response_sender.Run(response.Pass());
216 }
217
218 void RunningApplicationObject::ExtensionProcessCreated(
219     const IPC::ChannelHandle& handle) {
220   ep_bp_channel_ = handle;
221   dbus::Signal signal(kRunningApplicationDBusInterface, "EPChannelCreated");
222   dbus_object()->SendSignal(&signal);
223 }
224
225 }  // namespace application
226 }  // namespace xwalk