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