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.
16 #include <gio/gunixfdlist.h>
18 #include "xwalk/application/tools/linux/dbus_connection.h"
19 #include "xwalk/application/tools/linux/xwalk_extension_process_launcher.h"
22 #include "xwalk/application/tools/linux/xwalk_launcher_tizen.h"
23 #include "xwalk/application/tools/linux/xwalk_tizen_user.h"
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";
33 static char* application_object_path;
35 static GMainLoop* mainloop;
36 static GDBusConnection* g_connection;
37 static GDBusObjectManager* g_running_apps_manager;
38 static XWalkExtensionProcessLauncher* ep_launcher = NULL;
42 static gboolean query_running = FALSE;
43 static gboolean fullscreen = FALSE;
44 static gchar** cmd_appid_or_url;
46 static GOptionEntry entries[] = {
47 { "running", 'r', 0, G_OPTION_ARG_NONE, &query_running,
48 "Check whether the application is running", NULL },
49 { "fullscreen", 'f', 0, G_OPTION_ARG_NONE, &fullscreen,
50 "Run the application as fullscreen", NULL },
51 { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &cmd_appid_or_url,
52 "ID of the application to be launched or URL to open", NULL },
56 static void object_removed(GDBusObjectManager* manager, GDBusObject* object,
58 const char* path = g_dbus_object_get_object_path(object);
60 if (g_strcmp0(path, application_object_path))
63 fprintf(stderr, "Application '%s' disappeared, exiting.\n", path);
66 g_main_loop_quit(mainloop);
69 static void on_app_properties_changed(GDBusProxy* proxy,
70 GVariant* changed_properties,
71 GStrv invalidated_properties,
73 const char* interface = g_dbus_proxy_get_interface_name(proxy);
75 fprintf(stderr, "properties changed %s\n", interface);
77 if (g_variant_n_children(changed_properties) == 0)
80 if (g_strcmp0(interface, xwalk_running_app_iface))
87 g_variant_get(changed_properties, "a{sv}", &iter);
89 while (g_variant_iter_loop(iter, "{&sv}", &key, &value)) {
90 if (g_strcmp0(key, "State"))
93 const gchar* state = g_variant_get_string(value, NULL);
95 fprintf(stderr, "Application state %s\n", state);
99 static gboolean init_extension_process_channel(GDBusProxy* app_proxy) {
100 if (ep_launcher->is_started())
103 // Get the client socket file descriptor from fd_list. The reply will
104 // contains an index to the list.
105 GUnixFDList* fd_list;
106 GVariant* res = g_dbus_proxy_call_with_unix_fd_list_sync(
107 app_proxy, "GetEPChannel", NULL, G_DBUS_CALL_FLAGS_NONE,
108 -1, NULL, &fd_list, NULL, NULL);
109 if (!res || g_variant_n_children(res) != 2)
112 const gchar* channel_id =
113 g_variant_get_string(g_variant_get_child_value(res, 0), NULL);
114 if (!channel_id || !strlen(channel_id))
117 gint32 client_fd_idx =
118 g_variant_get_handle(g_variant_get_child_value(res, 1));
119 int client_fd = g_unix_fd_list_get(fd_list, client_fd_idx, NULL);
121 ep_launcher->Launch(channel_id, client_fd);
125 static void on_app_signal(GDBusProxy* proxy,
128 GVariant* parameters,
129 gpointer user_data) {
130 if (!strcmp(signal_name, "EPChannelCreated")) {
131 init_extension_process_channel(proxy);
133 fprintf(stderr, "Unkown signal received: %s\n", signal_name);
137 static int query_application_running(const char* app_id) {
138 GList* objects = g_dbus_object_manager_get_objects(g_running_apps_manager);
140 bool is_running = FALSE;
142 for (it = objects; it; it = it->next) {
143 GDBusObject* object = reinterpret_cast<GDBusObject*>(it->data);
144 GDBusInterface* iface = g_dbus_object_get_interface(
146 xwalk_running_app_iface);
150 GDBusProxy* proxy = G_DBUS_PROXY(iface);
151 GVariant* id_variant;
152 id_variant = g_dbus_proxy_get_cached_property(proxy, "AppID");
154 g_object_unref(iface);
159 g_variant_get(id_variant, "s", &id);
160 if (!strcmp(app_id, id)) {
165 g_object_unref(iface);
167 const char* str = is_running ? "running" : "not running";
168 g_print("Application %s is %s.\n", app_id, str);
170 g_list_free_full(objects, g_object_unref);
171 return is_running ? 0 : 1;
174 static void launch_application(const char* appid_or_url,
175 gboolean fullscreen) {
176 ep_launcher = new XWalkExtensionProcessLauncher();
177 GError* error = NULL;
178 g_signal_connect(g_running_apps_manager, "object-removed",
179 G_CALLBACK(object_removed), NULL);
181 GDBusProxy* running_proxy = g_dbus_proxy_new_sync(
183 G_DBUS_PROXY_FLAGS_NONE, NULL, xwalk_service_name,
184 xwalk_running_path, xwalk_running_manager_iface, NULL, &error);
185 if (!running_proxy) {
186 g_print("Couldn't create proxy for '%s': %s\n", xwalk_running_manager_iface,
192 unsigned int launcher_pid = getpid();
194 GVariant* result = g_dbus_proxy_call_sync(running_proxy, "Launch",
195 g_variant_new("(sub)", appid_or_url, launcher_pid, fullscreen),
196 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
198 fprintf(stderr, "Couldn't call 'Launch' method: %s\n", error->message);
202 g_variant_get(result, "(o)", &application_object_path);
203 fprintf(stderr, "Application launched with path '%s'\n",
204 application_object_path);
206 GDBusProxy* app_proxy = g_dbus_proxy_new_sync(
208 G_DBUS_PROXY_FLAGS_NONE, NULL, xwalk_service_name,
209 application_object_path, xwalk_running_app_iface, NULL, &error);
211 g_print("Couldn't create proxy for '%s': %s\n", xwalk_running_app_iface,
217 g_signal_connect(app_proxy, "g-properties-changed",
218 G_CALLBACK(on_app_properties_changed), NULL);
220 mainloop = g_main_loop_new(NULL, FALSE);
221 g_signal_connect(app_proxy, "g-signal", G_CALLBACK(on_app_signal), NULL);
223 #if defined(OS_TIZEN)
225 snprintf(name, sizeof(name), "xwalk-%s", appid_or_url);
227 if (xwalk_appcore_init(g_argc, g_argv, name, app_proxy)) {
228 fprintf(stderr, "Failed to initialize appcore");
233 init_extension_process_channel(app_proxy);
234 g_main_loop_run(mainloop);
237 void connect_to_application_manager() {
238 GError* error = NULL;
239 g_connection = get_session_bus_connection(&error);
241 fprintf(stderr, "Couldn't get the session bus connection: %s\n",
246 g_running_apps_manager =
247 g_dbus_object_manager_client_new_sync(
248 g_connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
249 xwalk_service_name, xwalk_running_path,
250 NULL, NULL, NULL, NULL, &error);
251 if (!g_running_apps_manager) {
252 fprintf(stderr, "Service '%s' does could not be reached: %s\n",
253 xwalk_service_name, error->message);
258 int main(int argc, char** argv) {
259 GError* error = NULL;
265 #if !GLIB_CHECK_VERSION(2, 36, 0)
266 // g_type_init() is deprecated on GLib since 2.36.
270 #if defined(OS_TIZEN)
271 if (xwalk_tizen_check_user_app())
275 GOptionContext* context =
276 g_option_context_new("- Crosswalk Application Launcher");
277 g_option_context_add_main_entries(context, entries, NULL);
278 if (!g_option_context_parse(context, &argc, &argv, &error)) {
279 fprintf(stderr, "Option parsing failed: %s\n", error->message);
283 connect_to_application_manager();
286 if (!strcmp(basename(argv[0]), "xwalk-launcher")) {
287 if (cmd_appid_or_url == NULL) {
288 fprintf(stderr, "No AppID informed, nothing to do.\n");
291 appid_or_url = strdup(cmd_appid_or_url[0]);
292 #if defined(OS_TIZEN)
293 if (GURL(appid_or_url).spec().empty()
294 && xwalk_change_cmdline(argc, argv, appid_or_url))
298 appid_or_url = strdup(basename(argv[0]));
304 return query_application_running(appid_or_url);
307 launch_application(appid_or_url, fullscreen);