Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / tools / linux / xwalk_launcher_main.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 <sys/types.h>
6 #include <stdlib.h>
7 #include <stdbool.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <pwd.h>
12 #include <libgen.h>
13
14 #include <glib.h>
15 #include <gio/gio.h>
16 #include <gio/gunixfdlist.h>
17
18 #include "xwalk/application/tools/linux/dbus_connection.h"
19 #include "xwalk/application/tools/linux/xwalk_extension_process_launcher.h"
20 #if defined(OS_TIZEN)
21 #include "url/gurl.h"
22 #include "xwalk/application/tools/linux/xwalk_launcher_tizen.h"
23 #include "xwalk/application/tools/tizen/xwalk_tizen_user.h"
24 #endif
25
26 static const char* xwalk_service_name = "org.crosswalkproject.Runtime1";
27 static const char* xwalk_running_path = "/running1";
28 static const char* xwalk_running_manager_iface =
29     "org.crosswalkproject.Running.Manager1";
30 static const char* xwalk_running_app_iface =
31     "org.crosswalkproject.Running.Application1";
32
33 static char* application_object_path;
34
35 static GMainLoop* mainloop;
36 static GDBusConnection* g_connection;
37 static GDBusObjectManager* g_running_apps_manager;
38 static XWalkExtensionProcessLauncher* ep_launcher = NULL;
39
40 static int g_argc;
41 static char** g_argv;
42 static gboolean query_running = FALSE;
43 static gboolean fullscreen = FALSE;
44 static gboolean remote_debugging = FALSE;
45 static gchar** cmd_appid_or_url;
46
47 static GOptionEntry entries[] = {
48   { "running", 'r', 0, G_OPTION_ARG_NONE, &query_running,
49     "Check whether the application is running", NULL },
50   { "fullscreen", 'f', 0, G_OPTION_ARG_NONE, &fullscreen,
51     "Run the application as fullscreen", NULL },
52   { "debugging_port", 'd', 0, G_OPTION_ARG_NONE, &remote_debugging,
53     "Enable remote debugging for the application", NULL },
54   { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &cmd_appid_or_url,
55     "ID of the application to be launched or URL to open", NULL },
56   { NULL }
57 };
58
59 static void object_removed(GDBusObjectManager* manager, GDBusObject* object,
60                            gpointer user_data) {
61   const char* path = g_dbus_object_get_object_path(object);
62
63   if (g_strcmp0(path, application_object_path))
64     return;
65
66   fprintf(stderr, "Application '%s' disappeared, exiting.\n", path);
67
68   delete ep_launcher;
69   g_main_loop_quit(mainloop);
70 }
71
72 static void on_app_properties_changed(GDBusProxy* proxy,
73                                       GVariant* changed_properties,
74                                       GStrv invalidated_properties,
75                                       gpointer user_data) {
76   const char* interface = g_dbus_proxy_get_interface_name(proxy);
77
78   fprintf(stderr, "properties changed %s\n", interface);
79
80   if (g_variant_n_children(changed_properties) == 0)
81     return;
82
83   if (g_strcmp0(interface, xwalk_running_app_iface))
84     return;
85
86   GVariantIter* iter;
87   const gchar* key;
88   GVariant* value;
89
90   g_variant_get(changed_properties, "a{sv}", &iter);
91
92   while (g_variant_iter_loop(iter, "{&sv}", &key, &value)) {
93     if (g_strcmp0(key, "State"))
94       continue;
95
96     const gchar* state = g_variant_get_string(value, NULL);
97
98     fprintf(stderr, "Application state %s\n", state);
99   }
100 }
101
102 static gboolean init_extension_process_channel(GDBusProxy* app_proxy) {
103   if (ep_launcher->is_started())
104     return FALSE;
105
106   // Get the client socket file descriptor from fd_list. The reply will
107   // contains an index to the list.
108   GUnixFDList* fd_list;
109   GVariant* res = g_dbus_proxy_call_with_unix_fd_list_sync(
110       app_proxy, "GetEPChannel", NULL, G_DBUS_CALL_FLAGS_NONE,
111       -1, NULL, &fd_list, NULL, NULL);
112   if (!res || g_variant_n_children(res) != 2)
113     return FALSE;
114
115   const gchar* channel_id =
116       g_variant_get_string(g_variant_get_child_value(res, 0), NULL);
117   if (!channel_id || !strlen(channel_id))
118     return FALSE;
119
120   gint32 client_fd_idx =
121       g_variant_get_handle(g_variant_get_child_value(res, 1));
122   int client_fd = g_unix_fd_list_get(fd_list, client_fd_idx, NULL);
123
124   ep_launcher->Launch(channel_id, client_fd);
125   return TRUE;
126 }
127
128 static void on_app_signal(GDBusProxy* proxy,
129                           gchar* sender_name,
130                           gchar* signal_name,
131                           GVariant* parameters,
132                           gpointer user_data) {
133   if (!strcmp(signal_name, "EPChannelCreated")) {
134     init_extension_process_channel(proxy);
135   } else {
136     fprintf(stderr, "Unkown signal received: %s\n", signal_name);
137   }
138 }
139
140 static int query_application_running(const char* app_id) {
141   GList* objects = g_dbus_object_manager_get_objects(g_running_apps_manager);
142   GList* it;
143   bool is_running = FALSE;
144
145   for (it = objects; it; it = it->next) {
146     GDBusObject* object = reinterpret_cast<GDBusObject*>(it->data);
147     GDBusInterface* iface = g_dbus_object_get_interface(
148         object,
149         xwalk_running_app_iface);
150     if (!iface)
151       continue;
152
153     GDBusProxy* proxy = G_DBUS_PROXY(iface);
154     GVariant* id_variant;
155     id_variant = g_dbus_proxy_get_cached_property(proxy, "AppID");
156     if (!id_variant) {
157       g_object_unref(iface);
158       continue;
159     }
160
161     const gchar* id;
162     g_variant_get(id_variant, "s", &id);
163     if (!strcmp(app_id, id)) {
164       is_running = TRUE;
165       break;
166     }
167
168     g_object_unref(iface);
169   }
170   const char* str = is_running ? "running" : "not running";
171   g_print("Application %s is %s.\n", app_id, str);
172
173   g_list_free_full(objects, g_object_unref);
174   return is_running ? 0 : 1;
175 }
176
177 static void launch_application(const char* appid_or_url,
178                                gboolean fullscreen,
179                                gboolean remote_debugging) {
180   ep_launcher = new XWalkExtensionProcessLauncher();
181   GError* error = NULL;
182   g_signal_connect(g_running_apps_manager, "object-removed",
183                    G_CALLBACK(object_removed), NULL);
184
185   GDBusProxy* running_proxy = g_dbus_proxy_new_sync(
186       g_connection,
187       G_DBUS_PROXY_FLAGS_NONE, NULL, xwalk_service_name,
188       xwalk_running_path, xwalk_running_manager_iface, NULL, &error);
189   if (!running_proxy) {
190     g_print("Couldn't create proxy for '%s': %s\n", xwalk_running_manager_iface,
191             error->message);
192     g_error_free(error);
193     exit(1);
194   }
195
196   unsigned int launcher_pid = getpid();
197
198   GVariant* result  = g_dbus_proxy_call_sync(running_proxy, "Launch",
199       g_variant_new("(subb)", appid_or_url, launcher_pid, fullscreen,
200                     remote_debugging),
201       G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
202   if (!result) {
203     fprintf(stderr, "Couldn't call 'Launch' method: %s\n", error->message);
204     exit(1);
205   }
206
207   g_variant_get(result, "(o)", &application_object_path);
208   fprintf(stderr, "Application launched with path '%s'\n",
209           application_object_path);
210
211   GDBusProxy* app_proxy = g_dbus_proxy_new_sync(
212       g_connection,
213       G_DBUS_PROXY_FLAGS_NONE, NULL, xwalk_service_name,
214       application_object_path, xwalk_running_app_iface, NULL, &error);
215   if (!app_proxy) {
216     g_print("Couldn't create proxy for '%s': %s\n", xwalk_running_app_iface,
217             error->message);
218     g_error_free(error);
219     exit(1);
220   }
221
222   g_signal_connect(app_proxy, "g-properties-changed",
223                    G_CALLBACK(on_app_properties_changed), NULL);
224
225   mainloop = g_main_loop_new(NULL, FALSE);
226   g_signal_connect(app_proxy, "g-signal", G_CALLBACK(on_app_signal), NULL);
227
228 #if defined(OS_TIZEN)
229   char name[128];
230   snprintf(name, sizeof(name), "xwalk-%s", appid_or_url);
231
232   if (xwalk_appcore_init(g_argc, g_argv, name, app_proxy)) {
233     fprintf(stderr, "Failed to initialize appcore");
234     exit(1);
235   }
236 #endif
237
238   init_extension_process_channel(app_proxy);
239   g_main_loop_run(mainloop);
240 }
241
242 void connect_to_application_manager() {
243   GError* error = NULL;
244   g_connection = get_session_bus_connection(&error);
245   if (!g_connection) {
246     fprintf(stderr, "Couldn't get the session bus connection: %s\n",
247             error->message);
248     exit(1);
249   }
250
251   g_running_apps_manager =
252       g_dbus_object_manager_client_new_sync(
253           g_connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
254           xwalk_service_name, xwalk_running_path,
255           NULL, NULL, NULL, NULL, &error);
256   if (!g_running_apps_manager) {
257     fprintf(stderr, "Service '%s' does could not be reached: %s\n",
258             xwalk_service_name, error->message);
259     exit(1);
260   }
261 }
262
263 int main(int argc, char** argv) {
264   GError* error = NULL;
265   char* appid_or_url;
266
267   g_argc = argc;
268   g_argv = argv;
269
270 #if !GLIB_CHECK_VERSION(2, 36, 0)
271   // g_type_init() is deprecated on GLib since 2.36.
272   g_type_init();
273 #endif
274
275 #if defined(OS_TIZEN)
276   if (xwalk_tizen_check_group_users())
277     exit(1);
278 #endif
279
280   GOptionContext* context =
281       g_option_context_new("- Crosswalk Application Launcher");
282   g_option_context_add_main_entries(context, entries, NULL);
283   if (!g_option_context_parse(context, &argc, &argv, &error)) {
284     fprintf(stderr, "Option parsing failed: %s\n", error->message);
285     exit(1);
286   }
287
288   connect_to_application_manager();
289
290   // Launch app.
291   if (!strcmp(basename(argv[0]), "xwalk-launcher")) {
292     if (cmd_appid_or_url == NULL) {
293       fprintf(stderr, "No AppID informed, nothing to do.\n");
294       return 0;
295     }
296     appid_or_url = strdup(cmd_appid_or_url[0]);
297 #if defined(OS_TIZEN)
298     if (GURL(appid_or_url).spec().empty()
299        && xwalk_change_cmdline(argc, argv, appid_or_url))
300       exit(1);
301 #endif
302   } else {
303     appid_or_url = strdup(basename(argv[0]));
304   }
305
306
307   // Query app.
308   if (query_running) {
309     return query_application_running(appid_or_url);
310   }
311
312   launch_application(appid_or_url, fullscreen, remote_debugging);
313   free(appid_or_url);
314   return 0;
315 }