Upstream version 11.39.264.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / tools / linux / dbus_object_manager.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/tools/linux/dbus_object_manager.h"
6
7 #include "base/message_loop/message_loop.h"
8
9 namespace {
10
11 const char kServiceName[] = "org.crosswalkproject.Runtime1";
12 const char kRunningManagerIface[] = "org.crosswalkproject.Running.Manager1";
13 const char kRunningAppIface[] = "org.crosswalkproject.Running.Application1";
14 const char kRunningManagerDBusPath[] = "/running1";
15 const char kEPChannelCreatedSignalName[] = "EPChannelCreated";
16
17 struct Properties : public dbus::PropertySet {
18   dbus::Property<std::string> app_id;
19
20   Properties(dbus::ObjectProxy* object_proxy,
21              const std::string& interface_name,
22              PropertyChangedCallback property_changed_callback)
23       : PropertySet(object_proxy, interface_name, property_changed_callback) {
24     RegisterProperty("AppID", &app_id);
25   }
26 };
27
28 }  // namespace
29
30 DBusObjectManager::DBusObjectManager(dbus::Bus* bus,
31                                      base::MessageLoop* main_loop)
32     : bus_(bus),
33       main_loop_(main_loop),
34       weak_ptr_factory_(this) {
35   ConnectToApplicationManager();
36 }
37
38 bool DBusObjectManager::Launch(const std::string& appid_or_url,
39      int launcher_pid, bool fullscreen, bool remote_debugging) {
40   if (!running_proxy_)
41     return false;
42   dbus::MethodCall method_call(
43       kRunningManagerIface, "Launch");
44   dbus::MessageWriter writer(&method_call);
45   writer.AppendString(appid_or_url);
46   writer.AppendUint32(launcher_pid);
47   writer.AppendBool(fullscreen);
48   writer.AppendBool(remote_debugging);
49   scoped_ptr<dbus::Response> response(
50       running_proxy_->CallMethodAndBlock(&method_call,
51       dbus::ObjectProxy::TIMEOUT_USE_DEFAULT));
52   if (!response.get())
53     return false;
54   if (!response->GetErrorName().empty()) {
55     LOG(ERROR) << "Error during call to 'Launch': "
56                << response->GetErrorName();
57     return false;
58   }
59
60   dbus::MessageReader reader(response.get());
61   dbus::ObjectPath running_application_path;
62   if (!reader.PopObjectPath(&running_application_path)) {
63     LOG(WARNING) << "Failed to create app proxy.";
64   } else {
65     app_proxy_ = bus_->GetObjectProxy(kServiceName, running_application_path);
66     if (app_proxy_)
67       ConnectToApplicationSignal(kEPChannelCreatedSignalName);
68   }
69   return true;
70 }
71
72 std::pair<std::string, int> DBusObjectManager::GetEPChannel() const {
73   std::pair<std::string, int> fd;
74   if (!app_proxy_) {
75     fd.second = -1;
76     return fd;
77   }
78   dbus::MethodCall method_call(kRunningAppIface, "GetEPChannel");
79   scoped_ptr<dbus::Response> response = app_proxy_->CallMethodAndBlock(
80       &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
81   const std::string& error = response->GetErrorName();
82   if (!error.empty()) {
83     LOG(ERROR) << "Error during call to 'GetEPChannel': "
84                << error;
85     fd.second = -1;
86     return fd;
87   }
88   dbus::MessageReader reader(response.release());
89   dbus::FileDescriptor extension_process_fd_;
90   if (!reader.PopString(&fd.first) ||
91       !reader.PopFileDescriptor(&extension_process_fd_)) {
92     LOG(ERROR) << "Couldn't get EP Channel";
93     fd.second = -1;
94     return fd;
95   }
96   extension_process_fd_.CheckValidity();
97   fd.second = extension_process_fd_.TakeValue();
98   return fd;
99 }
100
101 bool DBusObjectManager::Suspend() {
102   if (!app_proxy_)
103     return false;
104   dbus::MethodCall method_call(kRunningAppIface, "Suspend");
105   scoped_ptr<dbus::Response> response = app_proxy_->CallMethodAndBlock(
106       &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
107   if (!response->GetErrorName().empty()) {
108     LOG(ERROR) << "Error during call to 'Suspend': "
109                << response->GetErrorName();
110     return false;
111   }
112   return true;
113 }
114
115 bool DBusObjectManager::Resume() {
116   if (!app_proxy_)
117     return false;
118   dbus::MethodCall method_call(kRunningAppIface, "Resume");
119   scoped_ptr<dbus::Response> response = app_proxy_->CallMethodAndBlock(
120       &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
121   if (!response->GetErrorName().empty()) {
122     LOG(ERROR) << "Error during call to 'Resume': "
123                << response->GetErrorName();
124     return false;
125   }
126   return true;
127 }
128
129 void DBusObjectManager::OnOwnershipCallback(const std::string& service_name,
130                                             bool success) {
131   LOG(WARNING) << "Couldn't get ownership of D-Bus service name: "
132                << service_name << ".";
133 }
134
135 void DBusObjectManager::ConnectToApplicationManager() {
136   running_apps_manager_ = bus_->GetObjectManager(kServiceName,
137       dbus::ObjectPath(kRunningManagerDBusPath));
138   running_apps_manager_->RegisterInterface(kRunningAppIface, this);
139   running_proxy_ = bus_->GetObjectProxy(kServiceName,
140       dbus::ObjectPath(kRunningManagerDBusPath));
141 }
142
143 void DBusObjectManager::ObjectAdded(const dbus::ObjectPath& object_path,
144     const std::string& interface_name) {
145 }
146
147 void DBusObjectManager::ObjectRemoved(const dbus::ObjectPath& object_path,
148     const std::string& interface_name) {
149   if (object_path != app_proxy_->object_path())
150     return;
151   LOG(INFO) << "Application '" << object_path.value()
152             << "' disappeared, exiting.";
153   main_loop_->QuitNow();
154 }
155
156 dbus::PropertySet* DBusObjectManager::CreateProperties(
157     dbus::ObjectProxy *object_proxy,
158     const dbus::ObjectPath& object_path,
159     const std::string& interface_name) {
160   Properties* properties = new Properties(
161       object_proxy, interface_name,
162       base::Bind(&DBusObjectManager::OnPropertyChanged,
163                  base::Unretained(this), object_path));
164   return static_cast<dbus::PropertySet*>(properties);
165 }
166
167 void DBusObjectManager::OnPropertyChanged(const dbus::ObjectPath& object_path,
168     const std::string& name) {
169   if (!running_apps_manager_)
170     ConnectToApplicationManager();
171 }
172
173 void DBusObjectManager::ConnectToApplicationSignal(
174     const std::string& signal_name) {
175   DCHECK(app_proxy_);
176   app_proxy_->ConnectToSignal(kRunningAppIface, signal_name,
177       base::Bind(&DBusObjectManager::OnAppSignal,
178                  weak_ptr_factory_.GetWeakPtr()),
179       base::Bind(&DBusObjectManager::OnAppSignalConnected,
180                  weak_ptr_factory_.GetWeakPtr()));
181 }
182
183 bool DBusObjectManager::IsApplicationRunning(const std::string& app_id) {
184   std::vector<dbus::ObjectPath> objects = running_apps_manager_->GetObjects();
185   bool is_running = false;
186   for (dbus::ObjectPath obj : objects) {
187     Properties* properties =
188         static_cast<Properties*>(
189             running_apps_manager_->GetProperties(
190                 obj, kRunningAppIface));
191     if (!properties)
192       continue;
193     if (properties->app_id.value() == app_id) {
194       is_running = true;
195       break;
196     }
197   }
198   LOG(INFO) << "Application " << app_id << " is "
199             << (is_running ? "running." : "not running.");
200   return is_running;
201 }
202
203 void DBusObjectManager::OnAppSignal(dbus::Signal* signal) {
204   std::string signal_name = signal->GetMember();
205   if (signal_name == kEPChannelCreatedSignalName) {
206     if (observer_)
207       observer_->OnEPChannelCreated();
208   } else {
209     LOG(INFO) << "Unknown signal received: " << signal_name;
210   }
211 }
212
213 void DBusObjectManager::OnAppSignalConnected(
214     const std::string& interface_name,
215     const std::string& signal_name,
216     bool success) {
217   if (!success)
218     LOG(WARNING) << "Failed to connect signal: " << signal_name;
219 }