Merge lp:~ted/ubuntu-app-launch/log-file into lp:ubuntu-app-launch/14.04

Proposed by Ted Gould
Status: Superseded
Proposed branch: lp:~ted/ubuntu-app-launch/log-file
Merge into: lp:ubuntu-app-launch/14.04
Diff against target: 2657 lines (+1148/-837)
23 files modified
CMakeLists.txt (+13/-24)
application-job.c (+99/-0)
application.conf.in (+1/-21)
debian/libupstart-app-launch2.symbols (+1/-0)
desktop-single-trace.tp (+0/-5)
desktop-single.c (+0/-68)
helpers-keyfile.c (+95/-0)
helpers.c (+0/-74)
libupstart-app-launch/CMakeLists.txt (+9/-0)
libupstart-app-launch/second-exec-core.c (+129/-87)
libupstart-app-launch/upstart-app-launch-trace.tp (+20/-0)
libupstart-app-launch/upstart-app-launch.c (+474/-240)
libupstart-app-launch/upstart-app-launch.h (+13/-0)
second-exec-trace.tp (+0/-16)
second-exec.c (+0/-40)
tests/CMakeLists.txt (+1/-18)
tests/applications/multiple.desktop (+8/-0)
tests/applications/single.desktop (+8/-0)
tests/libual-test.cc (+272/-39)
tests/link-farm/README (+3/-0)
tests/link-farm/foo.desktop (+1/-0)
tests/link-farm/foolike.desktop (+1/-0)
tests/second-exec-test.cc (+0/-205)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/log-file
Reviewer Review Type Date Requested Status
Indicator Applet Developers Pending
Review via email: mp+205241@code.launchpad.net

This proposal has been superseded by a proposal from 2014-02-06.

Commit message

Function to get the log file for the application

Description of the change

Small function for QA so they don't have to know what is a Click app and what is not. Abstracts all that out for them.

To post a comment you must log in.
lp:~ted/ubuntu-app-launch/log-file updated
142. By Ted Gould

Merge future trunk

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-01-06 15:21:25 +0000
3+++ CMakeLists.txt 2014-02-06 18:42:36 +0000
4@@ -51,9 +51,12 @@
5 pkg_check_modules(ZEITGEIST REQUIRED zeitgeist-2.0)
6 include_directories(${ZEITGEIST_INCLUDE_DIRS})
7
8-pkg_check_modules(LIBUPSTART REQUIRED libupstart libnih libnih-dbus dbus-1)
9+pkg_check_modules(LIBUPSTART REQUIRED libupstart)
10 include_directories(${LIBUPSTART_INCLUDE_DIRS})
11
12+pkg_check_modules(DBUS REQUIRED dbus-1)
13+include_directories(${DBUS_INCLUDE_DIRS})
14+
15 pkg_check_modules(DBUSTEST REQUIRED dbustest-1>=14.04.0)
16 include_directories(${DBUSTEST_INCLUDE_DIRS})
17
18@@ -68,7 +71,7 @@
19 # Helpers
20 ####################
21
22-add_library(helpers STATIC helpers.c)
23+add_library(helpers STATIC helpers.c helpers-keyfile.c)
24 target_link_libraries(helpers ${GIO2_LIBRARIES} ${JSONGLIB_LIBRARIES})
25
26 ####################
27@@ -146,16 +149,6 @@
28 install(TARGETS desktop-hook RUNTIME DESTINATION "${pkglibexecdir}")
29
30 ####################
31-# desktop-single
32-####################
33-
34-add_lttng_gen_tp(NAME desktop-single-trace)
35-add_executable(desktop-single desktop-single.c desktop-single-trace.c)
36-set_target_properties(desktop-single PROPERTIES OUTPUT_NAME "desktop-single")
37-target_link_libraries(desktop-single helpers ${LTTNG_LIBRARIES})
38-install(TARGETS desktop-single RUNTIME DESTINATION "${pkglibexecdir}")
39-
40-####################
41 # exec-line-exec
42 ####################
43
44@@ -175,18 +168,14 @@
45 target_link_libraries(zg-report-app ${ZEITGEIST_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GLIB2_LIBRARIES})
46 install(TARGETS zg-report-app RUNTIME DESTINATION "${pkglibexecdir}")
47
48-#######################
49-# second-exec
50-#######################
51-
52-add_lttng_gen_tp(NAME second-exec-trace)
53-add_library(second-exec-core STATIC second-exec-core.c second-exec-trace.c)
54-target_link_libraries(second-exec-core helpers upstart-launcher ${LTTNG_LIBRARIES})
55-
56-add_executable(second-exec second-exec.c)
57-set_target_properties(second-exec PROPERTIES OUTPUT_NAME "second-exec")
58-target_link_libraries(second-exec second-exec-core)
59-install(TARGETS second-exec RUNTIME DESTINATION "${pkglibexecdir}")
60+####################
61+# application-job
62+####################
63+
64+add_executable(application-job application-job.c)
65+set_target_properties(application-job PROPERTIES OUTPUT_NAME "application-job")
66+target_link_libraries(application-job upstart-launcher)
67+install(TARGETS application-job RUNTIME DESTINATION "${pkglibexecdir}")
68
69 ####################
70 # application.conf
71
72=== added file 'application-job.c'
73--- application-job.c 1970-01-01 00:00:00 +0000
74+++ application-job.c 2014-02-06 18:42:36 +0000
75@@ -0,0 +1,99 @@
76+/*
77+ * Copyright 2013 Canonical Ltd.
78+ *
79+ * This program is free software: you can redistribute it and/or modify it
80+ * under the terms of the GNU General Public License version 3, as published
81+ * by the Free Software Foundation.
82+ *
83+ * This program is distributed in the hope that it will be useful, but
84+ * WITHOUT ANY WARRANTY; without even the implied warranties of
85+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
86+ * PURPOSE. See the GNU General Public License for more details.
87+ *
88+ * You should have received a copy of the GNU General Public License along
89+ * with this program. If not, see <http://www.gnu.org/licenses/>.
90+ *
91+ * Authors:
92+ * Ted Gould <ted.gould@canonical.com>
93+ */
94+
95+#include <gio/gio.h>
96+#include "libupstart-app-launch/upstart-app-launch.h"
97+
98+int retval = 0;
99+const gchar * global_appid;
100+
101+static void
102+app_started (const gchar * appid, gpointer user_data)
103+{
104+ if (g_strcmp0(appid, global_appid) != 0)
105+ return;
106+ g_debug("Application Started: %s", appid);
107+ g_main_loop_quit((GMainLoop *)user_data);
108+}
109+
110+static void
111+app_focus (const gchar * appid, gpointer user_data)
112+{
113+ if (g_strcmp0(appid, global_appid) != 0)
114+ return;
115+ g_debug("Application Focused");
116+ g_main_loop_quit((GMainLoop *)user_data);
117+}
118+
119+static void
120+app_failed (const gchar * appid, upstart_app_launch_app_failed_t failure_type, gpointer user_data)
121+{
122+ if (g_strcmp0(appid, global_appid) != 0)
123+ return;
124+ g_warning("Application Startup Failed");
125+ retval = 1;
126+ g_main_loop_quit((GMainLoop *)user_data);
127+}
128+
129+int
130+main (int argc, char * argv[])
131+{
132+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
133+ g_return_val_if_fail(con != NULL, 1);
134+
135+ global_appid = g_getenv("APP_ID");
136+ g_return_val_if_fail(global_appid != NULL, 1);
137+
138+ const gchar * uris_str = g_getenv("APP_URIS");
139+ gchar ** uris = NULL;
140+ if (uris_str != NULL) {
141+ GError * error = NULL;
142+ gint uri_count = 0;
143+ g_shell_parse_argv(uris_str, &uri_count, &uris, &error);
144+
145+ if (error != NULL) {
146+ g_warning("Unable to parse uris '%s': %s", uris_str, error->message);
147+ g_error_free(error);
148+ } else {
149+ g_debug("Got %d URIs", uri_count);
150+ }
151+ }
152+
153+ GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
154+
155+ upstart_app_launch_observer_add_app_started(app_started, mainloop);
156+ upstart_app_launch_observer_add_app_focus(app_focus, mainloop);
157+ upstart_app_launch_observer_add_app_failed(app_failed, mainloop);
158+
159+ g_debug("Start Application: %s", global_appid);
160+ g_return_val_if_fail(upstart_app_launch_start_application(global_appid, (const gchar * const *)uris), -1);
161+ g_strfreev(uris);
162+
163+ g_debug("Wait for results");
164+ g_main_loop_run(mainloop);
165+
166+ upstart_app_launch_observer_delete_app_started(app_started, mainloop);
167+ upstart_app_launch_observer_delete_app_focus(app_focus, mainloop);
168+ upstart_app_launch_observer_delete_app_failed(app_failed, mainloop);
169+
170+ g_main_loop_unref(mainloop);
171+ g_object_unref(con);
172+
173+ return retval;
174+}
175
176=== modified file 'application.conf.in'
177--- application.conf.in 2014-01-22 22:48:58 +0000
178+++ application.conf.in 2014-02-06 18:42:36 +0000
179@@ -14,24 +14,4 @@
180 env APP_URIS
181 export APP_URIS
182
183-script
184- CLICK_PKG=`echo "${APP_ID}" | cut -d _ -f 1`
185-
186- if [ ! -z $CLICK_PKG ] ; then
187- CLICK_DIR=`click pkgdir "${CLICK_PKG}" 2> /dev/null || true`
188- fi
189-
190- if [ ! -z $CLICK_DIR ] && [ -d $CLICK_DIR ] ; then
191- if ! start application-click APP_ID="${APP_ID}" APP_URIS="${APP_URIS}"; then
192- @pkglibexecdir@/second-exec
193- fi
194- else
195- if @pkglibexecdir@/desktop-single $APP_ID ; then
196- if ! start application-legacy APP_ID="${APP_ID}" INSTANCE_ID="" APP_URIS="${APP_URIS}" ; then
197- @pkglibexecdir@/second-exec
198- fi
199- else
200- start application-legacy APP_ID="${APP_ID}" INSTANCE_ID=`date -u +%s` APP_URIS="${APP_URIS}"
201- fi
202- fi
203-end script
204+exec @pkglibexecdir@/application-job
205
206=== modified file 'debian/libupstart-app-launch2.symbols'
207--- debian/libupstart-app-launch2.symbols 2014-01-29 20:08:07 +0000
208+++ debian/libupstart-app-launch2.symbols 2014-02-06 18:42:36 +0000
209@@ -1,4 +1,5 @@
210 libupstart-app-launch.so.2 libupstart-app-launch2 #MINVER#
211+ upstart_app_launch_application_log_path@Base 0replaceme
212 upstart_app_launch_get_primary_pid@Base 0.2
213 upstart_app_launch_list_running_apps@Base 0.2
214 upstart_app_launch_observer_add_app_failed@Base 0.2
215
216=== removed file 'desktop-single-trace.tp'
217--- desktop-single-trace.tp 2013-12-04 17:10:57 +0000
218+++ desktop-single-trace.tp 1970-01-01 00:00:00 +0000
219@@ -1,5 +0,0 @@
220-
221-TRACEPOINT_EVENT(upstart_app_launch, desktop_single_start, TP_ARGS(0), TP_FIELDS())
222-TRACEPOINT_EVENT(upstart_app_launch, desktop_single_found, TP_ARGS(0), TP_FIELDS())
223-TRACEPOINT_EVENT(upstart_app_launch, desktop_single_finished, TP_ARGS(0), TP_FIELDS())
224-
225
226=== removed file 'desktop-single.c'
227--- desktop-single.c 2013-12-05 17:08:13 +0000
228+++ desktop-single.c 1970-01-01 00:00:00 +0000
229@@ -1,68 +0,0 @@
230-/*
231- * Copyright 2013 Canonical Ltd.
232- *
233- * This program is free software: you can redistribute it and/or modify it
234- * under the terms of the GNU General Public License version 3, as published
235- * by the Free Software Foundation.
236- *
237- * This program is distributed in the hope that it will be useful, but
238- * WITHOUT ANY WARRANTY; without even the implied warranties of
239- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
240- * PURPOSE. See the GNU General Public License for more details.
241- *
242- * You should have received a copy of the GNU General Public License along
243- * with this program. If not, see <http://www.gnu.org/licenses/>.
244- *
245- * Authors:
246- * Ted Gould <ted.gould@canonical.com>
247- */
248-
249-#include "helpers.h"
250-#include "desktop-single-trace.h"
251-
252-int
253-main (int argc, char * argv[])
254-{
255- /* Nothing is single instance yet */
256- if (argc != 2) {
257- g_error("Should be called as: %s <app_id>", argv[0]);
258- return 1;
259- }
260-
261- g_setenv("LTTNG_UST_REGISTER_TIMEOUT", "0", FALSE); /* Set to zero if not set */
262- tracepoint(upstart_app_launch, desktop_single_start);
263-
264- GKeyFile * keyfile = keyfile_for_appid(argv[1], NULL);
265-
266- if (keyfile == NULL) {
267- g_error("Unable to find keyfile for application '%s'", argv[0]);
268- return 1;
269- }
270-
271- tracepoint(upstart_app_launch, desktop_single_found);
272-
273- gboolean singleinstance = FALSE;
274-
275- if (g_key_file_has_key(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", NULL)) {
276- GError * error = NULL;
277-
278- singleinstance = g_key_file_get_boolean(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", &error);
279-
280- if (error != NULL) {
281- g_warning("Unable to get single instance key for app '%s': %s", argv[1], error->message);
282- g_error_free(error);
283- /* Ensure that if we got an error, we assume standard case */
284- singleinstance = FALSE;
285- }
286- }
287-
288- g_key_file_free(keyfile);
289-
290- tracepoint(upstart_app_launch, desktop_single_finished);
291-
292- if (singleinstance) {
293- return 0;
294- } else {
295- return 1;
296- }
297-}
298
299=== added file 'helpers-keyfile.c'
300--- helpers-keyfile.c 1970-01-01 00:00:00 +0000
301+++ helpers-keyfile.c 2014-02-06 18:42:36 +0000
302@@ -0,0 +1,95 @@
303+/*
304+ * Copyright 2013 Canonical Ltd.
305+ *
306+ * This program is free software: you can redistribute it and/or modify it
307+ * under the terms of the GNU General Public License version 3, as published
308+ * by the Free Software Foundation.
309+ *
310+ * This program is distributed in the hope that it will be useful, but
311+ * WITHOUT ANY WARRANTY; without even the implied warranties of
312+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
313+ * PURPOSE. See the GNU General Public License for more details.
314+ *
315+ * You should have received a copy of the GNU General Public License along
316+ * with this program. If not, see <http://www.gnu.org/licenses/>.
317+ *
318+ * Authors:
319+ * Ted Gould <ted.gould@canonical.com>
320+ */
321+
322+#include "helpers.h"
323+
324+/* Check to make sure we have the sections and keys we want */
325+static gboolean
326+verify_keyfile (GKeyFile * inkeyfile, const gchar * desktop)
327+{
328+ if (inkeyfile == NULL) return FALSE;
329+
330+ if (!g_key_file_has_group(inkeyfile, "Desktop Entry")) {
331+ g_warning("Desktop file '%s' is missing the 'Desktop Entry' group", desktop);
332+ return FALSE;
333+ }
334+
335+ if (!g_key_file_has_key(inkeyfile, "Desktop Entry", "Exec", NULL)) {
336+ g_warning("Desktop file '%s' is missing the 'Exec' key", desktop);
337+ return FALSE;
338+ }
339+
340+ return TRUE;
341+}
342+
343+/* Try to find a desktop file in a particular data directory */
344+static GKeyFile *
345+try_dir (const char * dir, const gchar * desktop)
346+{
347+ gchar * fullpath = g_build_filename(dir, "applications", desktop, NULL);
348+ GKeyFile * keyfile = g_key_file_new();
349+
350+ /* NOTE: Leaving off the error here as we'll get a bunch of them,
351+ so individuals aren't really useful */
352+ gboolean loaded = g_key_file_load_from_file(keyfile, fullpath, G_KEY_FILE_NONE, NULL);
353+
354+ g_free(fullpath);
355+
356+ if (!loaded) {
357+ g_key_file_free(keyfile);
358+ return NULL;
359+ }
360+
361+ if (!verify_keyfile(keyfile, desktop)) {
362+ g_key_file_free(keyfile);
363+ return NULL;
364+ }
365+
366+ return keyfile;
367+}
368+
369+/* Find the keyfile that we need for a particular AppID and return it.
370+ Or NULL if we can't find it. */
371+GKeyFile *
372+keyfile_for_appid (const gchar * appid, gchar ** desktopfile)
373+{
374+ gchar * desktop = g_strdup_printf("%s.desktop", appid);
375+
376+ const char * const * data_dirs = g_get_system_data_dirs();
377+ GKeyFile * keyfile = NULL;
378+ int i;
379+
380+ keyfile = try_dir(g_get_user_data_dir(), desktop);
381+ if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
382+ *desktopfile = g_build_filename(g_get_user_data_dir(), "applications", desktop, NULL);
383+ }
384+
385+ for (i = 0; data_dirs[i] != NULL && keyfile == NULL; i++) {
386+ keyfile = try_dir(data_dirs[i], desktop);
387+
388+ if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
389+ *desktopfile = g_build_filename(data_dirs[i], "applications", desktop, NULL);
390+ }
391+ }
392+
393+ g_free(desktop);
394+
395+ return keyfile;
396+}
397+
398
399=== modified file 'helpers.c'
400--- helpers.c 2013-12-12 16:57:37 +0000
401+++ helpers.c 2014-02-06 18:42:36 +0000
402@@ -468,80 +468,6 @@
403 return newargv;
404 }
405
406-/* Check to make sure we have the sections and keys we want */
407-static gboolean
408-verify_keyfile (GKeyFile * inkeyfile, const gchar * desktop)
409-{
410- if (inkeyfile == NULL) return FALSE;
411-
412- if (!g_key_file_has_group(inkeyfile, "Desktop Entry")) {
413- g_warning("Desktop file '%s' is missing the 'Desktop Entry' group", desktop);
414- return FALSE;
415- }
416-
417- if (!g_key_file_has_key(inkeyfile, "Desktop Entry", "Exec", NULL)) {
418- g_warning("Desktop file '%s' is missing the 'Exec' key", desktop);
419- return FALSE;
420- }
421-
422- return TRUE;
423-}
424-
425-/* Try to find a desktop file in a particular data directory */
426-static GKeyFile *
427-try_dir (const char * dir, const gchar * desktop)
428-{
429- gchar * fullpath = g_build_filename(dir, "applications", desktop, NULL);
430- GKeyFile * keyfile = g_key_file_new();
431-
432- /* NOTE: Leaving off the error here as we'll get a bunch of them,
433- so individuals aren't really useful */
434- gboolean loaded = g_key_file_load_from_file(keyfile, fullpath, G_KEY_FILE_NONE, NULL);
435-
436- g_free(fullpath);
437-
438- if (!loaded) {
439- g_key_file_free(keyfile);
440- return NULL;
441- }
442-
443- if (!verify_keyfile(keyfile, desktop)) {
444- g_key_file_free(keyfile);
445- return NULL;
446- }
447-
448- return keyfile;
449-}
450-
451-/* Find the keyfile that we need for a particular AppID and return it.
452- Or NULL if we can't find it. */
453-GKeyFile *
454-keyfile_for_appid (const gchar * appid, gchar ** desktopfile)
455-{
456- gchar * desktop = g_strdup_printf("%s.desktop", appid);
457-
458- const char * const * data_dirs = g_get_system_data_dirs();
459- GKeyFile * keyfile = NULL;
460- int i;
461-
462- keyfile = try_dir(g_get_user_data_dir(), desktop);
463- if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
464- *desktopfile = g_build_filename(g_get_user_data_dir(), "applications", desktop, NULL);
465- }
466-
467- for (i = 0; data_dirs[i] != NULL && keyfile == NULL; i++) {
468- keyfile = try_dir(data_dirs[i], desktop);
469-
470- if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
471- *desktopfile = g_build_filename(data_dirs[i], "applications", desktop, NULL);
472- }
473- }
474-
475- g_free(desktop);
476-
477- return keyfile;
478-}
479-
480 /* Set environment various variables to make apps work under
481 * confinement according to:
482 * https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement
483
484=== modified file 'libupstart-app-launch/CMakeLists.txt'
485--- libupstart-app-launch/CMakeLists.txt 2014-01-13 15:16:24 +0000
486+++ libupstart-app-launch/CMakeLists.txt 2014-02-06 18:42:36 +0000
487@@ -1,4 +1,7 @@
488
489+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
490+include_directories(${CMAKE_CURRENT_BINARY_DIR})
491+
492 ##########################
493 # Version Info
494 ##########################
495@@ -11,6 +14,8 @@
496 # Library
497 ##########################
498
499+add_lttng_gen_tp(NAME upstart-app-launch-trace)
500+
501 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
502
503 set(LAUNCHER_HEADERS
504@@ -19,6 +24,9 @@
505
506 set(LAUNCHER_SOURCES
507 upstart-app-launch.c
508+second-exec-core.c
509+upstart-app-launch-trace.c
510+"${CMAKE_SOURCE_DIR}/helpers-keyfile.c"
511 )
512
513 add_library(upstart-launcher SHARED ${LAUNCHER_SOURCES})
514@@ -34,6 +42,7 @@
515 ${GOBJECT2_LIBRARIES}
516 ${LIBUPSTART_LIBRARIES}
517 ${GIO2_LIBRARIES}
518+ ${LTTNG_LIBRARIES}
519 ${JSONGLIB_LIBRARIES}
520 -Wl,--no-undefined
521 )
522
523=== renamed file 'second-exec-core.c' => 'libupstart-app-launch/second-exec-core.c'
524--- second-exec-core.c 2013-12-06 10:38:35 +0000
525+++ libupstart-app-launch/second-exec-core.c 2014-02-06 18:42:36 +0000
526@@ -23,18 +23,21 @@
527 #include "libupstart-app-launch/upstart-app-launch.h"
528 #include "helpers.h"
529 #include "second-exec-core.h"
530-#include "second-exec-trace.h"
531-
532-/* Globals */
533-GPid app_pid = 0;
534-GMainLoop * mainloop = NULL;
535-guint connections_open = 0;
536-const gchar * appid = NULL;
537-const gchar * input_uris = NULL;
538-GVariant * app_data = NULL;
539-gchar * dbus_path = NULL;
540-guint64 unity_starttime = 0;
541-guint timer = 0;
542+#include "upstart-app-launch-trace.h"
543+
544+typedef struct {
545+ GDBusConnection * bus;
546+ gchar * appid;
547+ gchar * input_uris;
548+ GPid app_pid;
549+ guint connections_open;
550+ GVariant * app_data;
551+ gchar * dbus_path;
552+ guint64 unity_starttime;
553+ guint timer;
554+} second_exec_t;
555+
556+static void second_exec_complete (second_exec_t * data);
557
558 /* Unity didn't respond in time, continue on */
559 static gboolean
560@@ -42,27 +45,27 @@
561 {
562 tracepoint(upstart_app_launch, second_exec_resume_timeout);
563 g_warning("Unity didn't respond in 500ms to resume the app");
564- g_main_loop_quit(mainloop);
565+ second_exec_complete(user_data);
566 return G_SOURCE_REMOVE;
567 }
568
569 /* Lower the connection count and process if it gets to zero */
570 static void
571-connection_count_dec (void)
572+connection_count_dec (second_exec_t * data)
573 {
574 tracepoint(upstart_app_launch, second_exec_connection_complete);
575- connections_open--;
576- if (connections_open == 0) {
577+ data->connections_open--;
578+ if (data->connections_open == 0) {
579 g_debug("Finished finding connections");
580 /* Check time here, either we've already heard from
581 Unity and we should send the data to the app (quit) or
582 we should wait some more */
583- guint64 timespent = g_get_monotonic_time() - unity_starttime;
584+ guint64 timespent = g_get_monotonic_time() - data->unity_starttime;
585 if (timespent > 500 /* ms */ * 1000 /* ms to us */) {
586- g_main_loop_quit(mainloop);
587+ second_exec_complete(data);
588 } else {
589 g_debug("Timer Set");
590- timer = g_timeout_add(500 - (timespent / 1000), timer_cb, NULL);
591+ data->timer = g_timeout_add(500 - (timespent / 1000), timer_cb, data);
592 }
593 }
594 return;
595@@ -73,18 +76,20 @@
596 static void
597 unity_resume_cb (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
598 {
599+ second_exec_t * data = (second_exec_t *)user_data;
600 g_debug("Unity Completed Resume");
601 tracepoint(upstart_app_launch, second_exec_resume_complete);
602
603- if (timer != 0) {
604- g_source_remove(timer);
605+ if (data->timer != 0) {
606+ g_source_remove(data->timer);
607+ data->timer = 0;
608 }
609
610- if (connections_open == 0) {
611- g_main_loop_quit(mainloop);
612+ if (data->connections_open == 0) {
613+ second_exec_complete(data);
614 } else {
615 /* Make it look like we started *forever* ago */
616- unity_starttime = 0;
617+ data->unity_starttime = 0;
618 }
619
620 return;
621@@ -92,9 +97,9 @@
622
623 /* Turn the input string into something we can send to apps */
624 static void
625-parse_uris (void)
626+parse_uris (second_exec_t * data)
627 {
628- if (app_data != NULL) {
629+ if (data->app_data != NULL) {
630 /* Already done */
631 return;
632 }
633@@ -103,11 +108,11 @@
634 gchar ** uri_split = NULL;
635 GError * error = NULL;
636
637- g_shell_parse_argv(input_uris, NULL, &uri_split, &error);
638+ g_shell_parse_argv(data->input_uris, NULL, &uri_split, &error);
639
640 if (uri_split == NULL || uri_split[0] == NULL || error != NULL) {
641 if (error != NULL) {
642- g_warning("Unable to parse URLs '%s': %s", input_uris, error->message);
643+ g_warning("Unable to parse URLs '%s': %s", data->input_uris, error->message);
644 g_error_free(error);
645 }
646
647@@ -136,8 +141,8 @@
648 g_variant_builder_add_value(&tuple, uris);
649 g_variant_builder_add_value(&tuple, platform);
650
651- app_data = g_variant_builder_end(&tuple);
652- g_variant_ref_sink(app_data);
653+ data->app_data = g_variant_builder_end(&tuple);
654+ g_variant_ref_sink(data->app_data);
655
656 return;
657 }
658@@ -149,14 +154,29 @@
659 http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus
660 */
661 static void
662-app_id_to_dbus_path (void)
663+app_id_to_dbus_path (second_exec_t * data)
664 {
665- if (dbus_path != NULL) {
666+ if (data->dbus_path != NULL) {
667 return;
668 }
669
670- dbus_path = nih_dbus_path(NULL, "", appid, NULL);
671- g_debug("DBus Path: %s", dbus_path);
672+ GString * str = g_string_sized_new(strlen(data->appid) + 2); /* base case, we just need a / and a null */
673+ g_string_append_c(str, '/');
674+
675+ int i;
676+ for (i = 0; data->appid[i] != '\0'; i++) {
677+ if ((data->appid[i] >= 'a' && data->appid[i] <= 'z') ||
678+ (data->appid[i] >= 'A' && data->appid[i] <= 'Z') ||
679+ (data->appid[i] >= '0' && data->appid[i] <= '9' && i != 0)) {
680+ g_string_append_c(str, data->appid[i]);
681+ continue;
682+ }
683+
684+ g_string_append_printf(str, "_%2x", data->appid[i]);
685+ }
686+
687+ data->dbus_path = g_string_free(str, FALSE);
688+ g_debug("DBus Path: %s", data->dbus_path);
689
690 return;
691 }
692@@ -178,43 +198,48 @@
693 g_error_free(error);
694 }
695
696- connection_count_dec();
697+ connection_count_dec(user_data);
698 return;
699 }
700
701 /* Sends the Open message to the connection with the URIs we were given */
702 static void
703-contact_app (GDBusConnection * bus, const gchar * dbus_name)
704+contact_app (GDBusConnection * bus, const gchar * dbus_name, second_exec_t * data)
705 {
706 tracepoint(upstart_app_launch, second_exec_contact_app);
707
708- parse_uris();
709- app_id_to_dbus_path();
710+ parse_uris(data);
711+ app_id_to_dbus_path(data);
712
713 /* Using the FD.o Application interface */
714 g_dbus_connection_call(bus,
715 dbus_name,
716- dbus_path,
717+ data->dbus_path,
718 "org.freedesktop.Application",
719 "Open",
720- app_data,
721+ data->app_data,
722 NULL,
723 G_DBUS_CALL_FLAGS_NONE,
724 -1,
725 NULL,
726- send_open_cb, NULL);
727+ send_open_cb, data);
728
729 g_debug("Sending Open request to: %s", dbus_name);
730
731 return;
732 }
733
734+typedef struct {
735+ gchar * name;
736+ second_exec_t * data;
737+} get_pid_t;
738+
739 /* Gets the PID for a connection, and if it matches the one we're looking
740 for then it tries to send a message to that connection */
741 static void
742 get_pid_cb (GObject * object, GAsyncResult * res, gpointer user_data)
743 {
744- gchar * dbus_name = (gchar *)user_data;
745+ get_pid_t * data = (get_pid_t *)user_data;
746 GError * error = NULL;
747 GVariant * vpid = NULL;
748
749@@ -223,12 +248,15 @@
750 vpid = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
751
752 if (error != NULL) {
753- g_warning("Unable to query PID for dbus name '%s': %s", dbus_name, error->message);
754+ g_warning("Unable to query PID for dbus name '%s': %s", data->name, error->message);
755 g_error_free(error);
756- g_free(dbus_name);
757
758 /* Lowering the connection count, this one is terminal, even if in error */
759- connection_count_dec();
760+ connection_count_dec(data->data);
761+
762+ g_free(data->name);
763+ g_free(data);
764+
765 return;
766 }
767
768@@ -236,22 +264,23 @@
769 g_variant_get(vpid, "(u)", &pid);
770 g_variant_unref(vpid);
771
772- if (pid == app_pid) {
773+ if (pid == data->data->app_pid) {
774 /* Trying to send a message to the connection */
775- contact_app(G_DBUS_CONNECTION(object), dbus_name);
776+ contact_app(G_DBUS_CONNECTION(object), data->name, data->data);
777 } else {
778 /* See if we can quit now */
779- connection_count_dec();
780+ connection_count_dec(data->data);
781 }
782
783- g_free(dbus_name);
784+ g_free(data->name);
785+ g_free(data);
786
787 return;
788 }
789
790 /* Starts to look for the PID and the connections for that PID */
791 void
792-find_appid_pid (GDBusConnection * session)
793+find_appid_pid (GDBusConnection * session, second_exec_t * data)
794 {
795 GError * error = NULL;
796
797@@ -276,18 +305,20 @@
798 return;
799 }
800
801+ g_debug("Got bus names");
802 tracepoint(upstart_app_launch, second_exec_got_dbus_names);
803
804 /* Next figure out what we're looking for (and if there is something to look for) */
805 /* NOTE: We're getting the PID *after* the list of connections so
806 that some new process can't come in, be the same PID as it's
807 connection will not be in teh list we just got. */
808- app_pid = upstart_app_launch_get_primary_pid(appid);
809- if (app_pid == 0) {
810- g_warning("Unable to find pid for app id '%s'", appid);
811+ data->app_pid = upstart_app_launch_get_primary_pid(data->appid);
812+ if (data->app_pid == 0) {
813+ g_warning("Unable to find pid for app id '%s'", data->appid);
814 return;
815 }
816
817+ g_debug("Primary PID: %d", data->app_pid);
818 tracepoint(upstart_app_launch, second_exec_got_primary_pid);
819
820 /* Get the names */
821@@ -301,6 +332,10 @@
822 if (!g_dbus_is_unique_name(name)) {
823 continue;
824 }
825+
826+ get_pid_t * pid_data = g_new0(get_pid_t, 1);
827+ pid_data->data = data;
828+ pid_data->name = g_strdup(name);
829
830 tracepoint(upstart_app_launch, second_exec_request_pid);
831
832@@ -315,9 +350,9 @@
833 G_DBUS_CALL_FLAGS_NONE,
834 -1,
835 NULL,
836- get_pid_cb, g_strdup(name));
837+ get_pid_cb, pid_data);
838
839- connections_open++;
840+ data->connections_open++;
841 }
842
843 g_variant_unref(names);
844@@ -329,9 +364,6 @@
845 gboolean
846 second_exec (const gchar * app_id, const gchar * appuris)
847 {
848- appid = app_id;
849- input_uris = appuris;
850-
851 tracepoint(upstart_app_launch, second_exec_start);
852
853 /* DBus tell us! */
854@@ -343,8 +375,11 @@
855 return FALSE;
856 }
857
858- /* Allocate main loop */
859- mainloop = g_main_loop_new(NULL, FALSE);
860+ /* Setup our continuation data */
861+ second_exec_t * data = g_new0(second_exec_t, 1);
862+ data->appid = g_strdup(app_id);
863+ data->input_uris = g_strdup(appuris);
864+ data->bus = session;
865
866 /* Set up listening for the unfrozen signal from Unity */
867 g_dbus_connection_signal_subscribe(session,
868@@ -352,11 +387,12 @@
869 "com.canonical.UpstartAppLaunch", /* interface */
870 "UnityResumeResponse", /* signal */
871 "/", /* path */
872- appid, /* arg0 */
873+ app_id, /* arg0 */
874 G_DBUS_SIGNAL_FLAGS_NONE,
875- unity_resume_cb, mainloop,
876+ unity_resume_cb, data,
877 NULL); /* user data destroy */
878
879+ g_debug("Sending resume request");
880 tracepoint(upstart_app_launch, second_exec_emit_resume);
881
882 /* Send unfreeze to to Unity */
883@@ -365,43 +401,49 @@
884 "/", /* path */
885 "com.canonical.UpstartAppLaunch", /* interface */
886 "UnityResumeRequest", /* signal */
887- g_variant_new("(s)", appid),
888+ g_variant_new("(s)", app_id),
889 &error);
890
891 /* Now we start a race, we try to get to the point of knowing who
892 to send things to, and Unity is unfrezing it. When both are
893 done we can send something to the app */
894- unity_starttime = g_get_monotonic_time();
895+ data->unity_starttime = g_get_monotonic_time();
896
897 if (error != NULL) {
898 /* On error let's not wait for Unity */
899 g_warning("Unable to signal Unity: %s", error->message);
900 g_error_free(error);
901 error = NULL;
902- unity_starttime = 0;
903+ data->unity_starttime = 0;
904 }
905
906 /* If we've got something to give out, start looking for how */
907- if (input_uris != NULL) {
908- find_appid_pid(session);
909+ if (data->input_uris != NULL) {
910+ find_appid_pid(session, data);
911 }
912
913 /* Loop and wait for everything to align */
914- if (connections_open > 0 || unity_starttime > 0) {
915- g_main_loop_run(mainloop);
916+ if (data->connections_open == 0 && data->unity_starttime == 0) {
917+ second_exec_complete(data);
918 }
919- g_debug("Finishing main loop");
920-
921+
922+ return TRUE;
923+}
924+
925+static void
926+second_exec_complete (second_exec_t * data)
927+{
928+ GError * error = NULL;
929 tracepoint(upstart_app_launch, second_exec_emit_focus);
930
931 /* Now that we're done sending the info to the app, we can ask
932 Unity to focus the application. */
933- g_dbus_connection_emit_signal(session,
934+ g_dbus_connection_emit_signal(data->bus,
935 NULL, /* destination */
936 "/", /* path */
937 "com.canonical.UpstartAppLaunch", /* interface */
938 "UnityFocusRequest", /* signal */
939- g_variant_new("(s)", appid),
940+ g_variant_new("(s)", data->appid),
941 &error);
942
943 if (error != NULL) {
944@@ -411,23 +453,23 @@
945 }
946
947 /* Make sure the signal hits the bus */
948- g_dbus_connection_flush_sync(session, NULL, NULL);
949+ g_dbus_connection_flush_sync(data->bus, NULL, &error);
950+ if (error != NULL) {
951+ g_warning("Unable to flush session bus: %s", error->message);
952+ g_error_free(error);
953+ error = NULL;
954+ }
955
956 /* Clean up */
957- if (app_data != NULL) {
958- g_variant_unref(app_data);
959- app_data = NULL;
960- }
961-
962- g_main_loop_unref(mainloop);
963- g_object_unref(session);
964-
965- if (dbus_path != NULL) {
966- nih_free(dbus_path);
967- dbus_path = NULL;
968- }
969+ g_object_unref(data->bus);
970+ if (data->app_data != NULL)
971+ g_variant_unref(data->app_data);
972+ g_free(data->appid);
973+ g_free(data->input_uris);
974+ g_free(data->dbus_path);
975+ g_free(data);
976
977 tracepoint(upstart_app_launch, second_exec_finish);
978
979- return TRUE;
980+ return;
981 }
982
983=== renamed file 'second-exec-core.h' => 'libupstart-app-launch/second-exec-core.h'
984=== added file 'libupstart-app-launch/upstart-app-launch-trace.tp'
985--- libupstart-app-launch/upstart-app-launch-trace.tp 1970-01-01 00:00:00 +0000
986+++ libupstart-app-launch/upstart-app-launch-trace.tp 2014-02-06 18:42:36 +0000
987@@ -0,0 +1,20 @@
988+
989+TRACEPOINT_EVENT(upstart_app_launch, second_exec_start, TP_ARGS(0), TP_FIELDS())
990+TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_resume, TP_ARGS(0), TP_FIELDS())
991+TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_complete, TP_ARGS(0), TP_FIELDS())
992+TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_timeout, TP_ARGS(0), TP_FIELDS())
993+TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_focus, TP_ARGS(0), TP_FIELDS())
994+TRACEPOINT_EVENT(upstart_app_launch, second_exec_finish, TP_ARGS(0), TP_FIELDS())
995+TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_dbus_names, TP_ARGS(0), TP_FIELDS())
996+TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_primary_pid, TP_ARGS(0), TP_FIELDS())
997+TRACEPOINT_EVENT(upstart_app_launch, second_exec_request_pid, TP_ARGS(0), TP_FIELDS())
998+TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_pid, TP_ARGS(0), TP_FIELDS())
999+TRACEPOINT_EVENT(upstart_app_launch, second_exec_contact_app, TP_ARGS(0), TP_FIELDS())
1000+TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_contacted, TP_ARGS(0), TP_FIELDS())
1001+TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_error, TP_ARGS(0), TP_FIELDS())
1002+TRACEPOINT_EVENT(upstart_app_launch, second_exec_connection_complete, TP_ARGS(0), TP_FIELDS())
1003+
1004+TRACEPOINT_EVENT(upstart_app_launch, desktop_single_start, TP_ARGS(0), TP_FIELDS())
1005+TRACEPOINT_EVENT(upstart_app_launch, desktop_single_found, TP_ARGS(0), TP_FIELDS())
1006+TRACEPOINT_EVENT(upstart_app_launch, desktop_single_finished, TP_ARGS(0), TP_FIELDS())
1007+
1008
1009=== modified file 'libupstart-app-launch/upstart-app-launch.c'
1010--- libupstart-app-launch/upstart-app-launch.c 2014-01-29 02:19:27 +0000
1011+++ libupstart-app-launch/upstart-app-launch.c 2014-02-06 18:42:36 +0000
1012@@ -20,53 +20,16 @@
1013 #include "upstart-app-launch.h"
1014 #include <json-glib/json-glib.h>
1015 #include <upstart.h>
1016-#include <nih/alloc.h>
1017-#include <nih/error.h>
1018 #include <gio/gio.h>
1019 #include <string.h>
1020
1021-static void apps_for_job (NihDBusProxy * upstart, const gchar * name, GArray * apps, gboolean truncate_legacy);
1022+#include "upstart-app-launch-trace.h"
1023+#include "second-exec-core.h"
1024+#include "../helpers.h"
1025+
1026+static void apps_for_job (GDBusConnection * con, const gchar * name, GArray * apps, gboolean truncate_legacy);
1027 static void free_helper (gpointer value);
1028
1029-static NihDBusProxy *
1030-nih_proxy_create (void)
1031-{
1032- NihDBusProxy * upstart;
1033- DBusConnection * conn;
1034- DBusError error;
1035- const gchar * bus_name = NULL;
1036-
1037- dbus_error_init(&error);
1038-
1039- conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
1040- bus_name = "com.ubuntu.Upstart";
1041-
1042- if (conn == NULL) {
1043- g_warning("Unable to connect to the Upstart Session: %s", error.message);
1044- dbus_error_free(&error);
1045- return NULL;
1046- }
1047-
1048- dbus_error_free(&error);
1049-
1050- upstart = nih_dbus_proxy_new(NULL, conn,
1051- bus_name,
1052- DBUS_PATH_UPSTART,
1053- NULL, NULL);
1054-
1055- if (upstart == NULL) {
1056- g_warning("Unable to build proxy to Upstart");
1057- dbus_connection_unref(conn);
1058- return NULL;
1059- }
1060-
1061- dbus_connection_unref(conn);
1062-
1063- upstart->auto_start = FALSE;
1064-
1065- return upstart;
1066-}
1067-
1068 /* Function to take the urls and escape them so that they can be
1069 parsed on the other side correctly. */
1070 static gchar *
1071@@ -87,83 +50,260 @@
1072 return urisjoin;
1073 }
1074
1075+typedef struct {
1076+ gchar * appid;
1077+ gchar * uris;
1078+} app_start_t;
1079+
1080+static void
1081+application_start_cb (GObject * obj, GAsyncResult * res, gpointer user_data)
1082+{
1083+ app_start_t * data = (app_start_t *)user_data;
1084+ GError * error = NULL;
1085+ GVariant * result = NULL;
1086+
1087+ g_debug("Started Message Callback: %s", data->appid);
1088+
1089+ result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
1090+
1091+ if (result != NULL)
1092+ g_variant_unref(result);
1093+
1094+ if (error != NULL) {
1095+ if (g_dbus_error_is_remote_error(error)) {
1096+ gchar * remote_error = g_dbus_error_get_remote_error(error);
1097+ g_debug("Remote error: %s", remote_error);
1098+ if (g_strcmp0(remote_error, "com.ubuntu.Upstart0_6.Error.AlreadyStarted") == 0) {
1099+ second_exec(data->appid, data->uris);
1100+ }
1101+
1102+ g_free(remote_error);
1103+ } else {
1104+ g_warning("Unable to emit event to start application: %s", error->message);
1105+ }
1106+ g_error_free(error);
1107+ }
1108+
1109+ g_free(data->appid);
1110+ g_free(data->uris);
1111+ g_free(data);
1112+}
1113+
1114+/* Get the path of the job from Upstart, if we've got it already, we'll just
1115+ use the cache of the value */
1116+static const gchar *
1117+get_jobpath (GDBusConnection * con, const gchar * jobname)
1118+{
1119+ gchar * cachepath = g_strdup_printf("upstart-app-lauch-job-path-cache-%s", jobname);
1120+ gpointer cachedata = g_object_get_data(G_OBJECT(con), cachepath);
1121+
1122+ if (cachedata != NULL) {
1123+ g_free(cachepath);
1124+ return cachedata;
1125+ }
1126+
1127+ GError * error = NULL;
1128+ GVariant * job_path_variant = g_dbus_connection_call_sync(con,
1129+ DBUS_SERVICE_UPSTART,
1130+ DBUS_PATH_UPSTART,
1131+ DBUS_INTERFACE_UPSTART,
1132+ "GetJobByName",
1133+ g_variant_new("(s)", jobname),
1134+ G_VARIANT_TYPE("(o)"),
1135+ G_DBUS_CALL_FLAGS_NONE,
1136+ -1, /* timeout: default */
1137+ NULL, /* cancelable */
1138+ &error);
1139+
1140+ if (error != NULL) {
1141+ g_warning("Unable to find job '%s': %s", jobname, error->message);
1142+ g_error_free(error);
1143+ g_free(cachepath);
1144+ return NULL;
1145+ }
1146+
1147+ gchar * job_path = NULL;
1148+ g_variant_get(job_path_variant, "(o)", &job_path);
1149+ g_variant_unref(job_path_variant);
1150+
1151+ g_object_set_data_full(G_OBJECT(con), cachepath, job_path, g_free);
1152+ g_free(cachepath);
1153+
1154+ return job_path;
1155+}
1156+
1157+/* Check to see if a legacy app wants us to manage whether they're
1158+ single instance or not */
1159+static gboolean
1160+legacy_single_instance (const gchar * appid)
1161+{
1162+ tracepoint(upstart_app_launch, desktop_single_start);
1163+
1164+ GKeyFile * keyfile = keyfile_for_appid(appid, NULL);
1165+
1166+ if (keyfile == NULL) {
1167+ g_warning("Unable to find keyfile for application '%s'", appid);
1168+ return FALSE;
1169+ }
1170+
1171+ tracepoint(upstart_app_launch, desktop_single_found);
1172+
1173+ gboolean singleinstance = FALSE;
1174+
1175+ if (g_key_file_has_key(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", NULL)) {
1176+ GError * error = NULL;
1177+
1178+ singleinstance = g_key_file_get_boolean(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", &error);
1179+
1180+ if (error != NULL) {
1181+ g_warning("Unable to get single instance key for app '%s': %s", appid, error->message);
1182+ g_error_free(error);
1183+ /* Ensure that if we got an error, we assume standard case */
1184+ singleinstance = FALSE;
1185+ }
1186+ }
1187+
1188+ g_key_file_free(keyfile);
1189+
1190+ tracepoint(upstart_app_launch, desktop_single_finished);
1191+
1192+ return singleinstance;
1193+}
1194+
1195+/* Determine whether it's a click package by looking for the symlink
1196+ that is created by the desktop hook */
1197+static gboolean
1198+is_click (const gchar * appid)
1199+{
1200+ gchar * appiddesktop = g_strdup_printf("%s.desktop", appid);
1201+ gchar * click_link = NULL;
1202+ const gchar * link_farm_dir = g_getenv("UPSTART_APP_LAUNCH_LINK_FARM");
1203+ if (G_LIKELY(link_farm_dir == NULL)) {
1204+ click_link = g_build_filename(g_get_home_dir(), ".cache", "upstart-app-launch", "desktop", appiddesktop, NULL);
1205+ } else {
1206+ click_link = g_build_filename(link_farm_dir, appiddesktop, NULL);
1207+ }
1208+ g_free(appiddesktop);
1209+ gboolean click = g_file_test(click_link, G_FILE_TEST_EXISTS);
1210+ g_free(click_link);
1211+
1212+ return click;
1213+}
1214+
1215 gboolean
1216 upstart_app_launch_start_application (const gchar * appid, const gchar * const * uris)
1217 {
1218- NihDBusProxy * proxy = NULL;
1219-
1220- proxy = nih_proxy_create();
1221- if (proxy == NULL) {
1222+ g_return_val_if_fail(appid != NULL, FALSE);
1223+
1224+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
1225+ g_return_val_if_fail(con != NULL, FALSE);
1226+
1227+ gboolean click = is_click(appid);
1228+
1229+ /* Figure out the DBus path for the job */
1230+ const gchar * jobpath = NULL;
1231+ if (click) {
1232+ jobpath = get_jobpath(con, "application-click");
1233+ } else {
1234+ jobpath = get_jobpath(con, "application-legacy");
1235+ }
1236+
1237+ if (jobpath == NULL)
1238 return FALSE;
1239- }
1240-
1241- gchar * env_appid = g_strdup_printf("APP_ID=%s", appid);
1242- gchar * env_uris = NULL;
1243+
1244+ /* Callback data */
1245+ app_start_t * app_start_data = g_new0(app_start_t, 1);
1246+ app_start_data->appid = g_strdup(appid);
1247+
1248+ /* Build up our environment */
1249+ GVariantBuilder builder;
1250+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
1251+
1252+ g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
1253+
1254+ g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("APP_ID=%s", appid)));
1255
1256 if (uris != NULL) {
1257 gchar * urisjoin = app_uris_string(uris);
1258- env_uris = g_strdup_printf("APP_URIS=%s", urisjoin);
1259- g_free(urisjoin);
1260- }
1261-
1262- gchar * env[3];
1263- env[0] = env_appid;
1264- env[1] = env_uris;
1265- env[2] = NULL;
1266-
1267- gboolean retval = TRUE;
1268- if (upstart_emit_event_sync(NULL, proxy, "application-start", env, 0) != 0) {
1269- g_warning("Unable to emit signal 'application-start'");
1270- retval = FALSE;
1271- }
1272-
1273- g_free(env_appid);
1274- g_free(env_uris);
1275- nih_unref(proxy, NULL);
1276-
1277- return retval;
1278+ gchar * urienv = g_strdup_printf("APP_URIS=%s", urisjoin);
1279+ app_start_data->uris = urisjoin;
1280+ g_variant_builder_add_value(&builder, g_variant_new_take_string(urienv));
1281+ }
1282+
1283+ if (!click) {
1284+ if (legacy_single_instance(appid)) {
1285+ g_variant_builder_add_value(&builder, g_variant_new_string("INSTANCE_ID="));
1286+ } else {
1287+ gchar * instanceid = g_strdup_printf("INSTANCE_ID=%" G_GUINT64_FORMAT, g_get_real_time());
1288+ g_variant_builder_add_value(&builder, g_variant_new_take_string(instanceid));
1289+ }
1290+ }
1291+
1292+ g_variant_builder_close(&builder);
1293+ g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
1294+
1295+ /* Call the job start function */
1296+ g_dbus_connection_call(con,
1297+ DBUS_SERVICE_UPSTART,
1298+ jobpath,
1299+ DBUS_INTERFACE_UPSTART_JOB,
1300+ "Start",
1301+ g_variant_builder_end(&builder),
1302+ NULL,
1303+ G_DBUS_CALL_FLAGS_NONE,
1304+ -1,
1305+ NULL, /* cancelable */
1306+ application_start_cb,
1307+ app_start_data);
1308+
1309+ g_object_unref(con);
1310+
1311+ return TRUE;
1312 }
1313
1314 static void
1315-stop_job (NihDBusProxy * upstart, const gchar * jobname, const gchar * appname, const gchar * instanceid)
1316+stop_job (GDBusConnection * con, const gchar * jobname, const gchar * appname, const gchar * instanceid)
1317 {
1318 g_debug("Stopping job %s app_id %s instance_id %s", jobname, appname, instanceid);
1319- nih_local char * job_path = NULL;
1320- if (upstart_get_job_by_name_sync(NULL, upstart, jobname, &job_path) != 0) {
1321- g_warning("Unable to find job '%s'", jobname);
1322- return;
1323- }
1324-
1325- NihDBusProxy * job_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
1326- upstart->name,
1327- job_path,
1328- NULL, NULL);
1329-
1330- if (job_proxy == NULL) {
1331- g_warning("Unable to build proxy to Job '%s'", jobname);
1332- return;
1333- }
1334-
1335- gchar * app = g_strdup_printf("APP_ID=%s", appname);
1336- gchar * inst = NULL;
1337+
1338+ const gchar * job_path = get_jobpath(con, jobname);
1339+ if (job_path == NULL)
1340+ return;
1341+
1342+ GVariantBuilder builder;
1343+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
1344+ g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
1345+
1346+ g_variant_builder_add_value(&builder,
1347+ g_variant_new_take_string(g_strdup_printf("APP_ID=%s", appname)));
1348
1349 if (instanceid != NULL) {
1350- inst = g_strdup_printf("INSTANCE_ID=%s", instanceid);
1351- }
1352-
1353- gchar * env[3] = {
1354- app,
1355- inst,
1356- NULL
1357- };
1358-
1359- if (job_class_stop_sync(NULL, job_proxy, env, 0) != 0) {
1360- g_warning("Unable to stop job %s app %s instance %s", jobname, appname, instanceid);
1361- }
1362-
1363- g_free(app);
1364- g_free(inst);
1365- nih_unref(job_proxy, NULL);
1366+ g_variant_builder_add_value(&builder,
1367+ g_variant_new_take_string(g_strdup_printf("INSTANCE_ID=%s", instanceid)));
1368+ }
1369+
1370+ g_variant_builder_close(&builder);
1371+ g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); /* wait */
1372+
1373+ GError * error = NULL;
1374+ GVariant * stop_variant = g_dbus_connection_call_sync(con,
1375+ DBUS_SERVICE_UPSTART,
1376+ job_path,
1377+ DBUS_INTERFACE_UPSTART_JOB,
1378+ "Stop",
1379+ g_variant_builder_end(&builder),
1380+ NULL,
1381+ G_DBUS_CALL_FLAGS_NONE,
1382+ -1, /* timeout: default */
1383+ NULL, /* cancelable */
1384+ &error);
1385+
1386+ if (error != NULL) {
1387+ g_warning("Unable to stop job %s app_id %s instance_id %s: %s", jobname, appname, instanceid, error->message);
1388+ g_error_free(error);
1389+ }
1390+
1391+ g_variant_unref(stop_variant);
1392 }
1393
1394 static void
1395@@ -176,25 +316,24 @@
1396 gboolean
1397 upstart_app_launch_stop_application (const gchar * appid)
1398 {
1399+ g_return_val_if_fail(appid != NULL, FALSE);
1400+
1401+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
1402+ g_return_val_if_fail(con != NULL, FALSE);
1403+
1404 gboolean found = FALSE;
1405 int i;
1406- NihDBusProxy * proxy = NULL;
1407-
1408- proxy = nih_proxy_create();
1409- if (proxy == NULL) {
1410- return FALSE;
1411- }
1412
1413 GArray * apps = g_array_new(TRUE, TRUE, sizeof(gchar *));
1414 g_array_set_clear_func(apps, free_helper);
1415
1416 /* Look through the click jobs and see if any match. There can
1417 only be one instance for each ID in the click world */
1418- apps_for_job(proxy, "application-click", apps, FALSE);
1419+ apps_for_job(con, "application-click", apps, FALSE);
1420 for (i = 0; i < apps->len; i++) {
1421 const gchar * array_id = g_array_index(apps, const gchar *, i);
1422 if (g_strcmp0(array_id, appid) == 0) {
1423- stop_job(proxy, "application-click", appid, NULL);
1424+ stop_job(con, "application-click", appid, NULL);
1425 found = TRUE;
1426 break; /* There can be only one with click */
1427 }
1428@@ -206,24 +345,71 @@
1429 /* Look through the legacy apps. Trickier because we know that there
1430 can be many instances of the legacy jobs out there, so we might
1431 have to kill more than one of them. */
1432- apps_for_job(proxy, "application-legacy", apps, FALSE);
1433+ apps_for_job(con, "application-legacy", apps, FALSE);
1434 gchar * appiddash = g_strdup_printf("%s-", appid); /* Probably could go RegEx here, but let's start with just a prefix lookup */
1435 for (i = 0; i < apps->len; i++) {
1436 const gchar * array_id = g_array_index(apps, const gchar *, i);
1437 if (g_str_has_prefix(array_id, appiddash)) {
1438 gchar * instanceid = g_strrstr(array_id, "-");
1439- stop_job(proxy, "application-legacy", appid, &(instanceid[1]));
1440+ stop_job(con, "application-legacy", appid, &(instanceid[1]));
1441 found = TRUE;
1442 }
1443 }
1444 g_free(appiddash);
1445
1446 g_array_free(apps, TRUE);
1447- nih_unref(proxy, NULL);
1448+ g_object_unref(con);
1449
1450 return found;
1451 }
1452
1453+gchar *
1454+upstart_app_launch_application_log_path (const gchar * appid)
1455+{
1456+ gchar * path = NULL;
1457+ g_return_val_if_fail(appid != NULL, NULL);
1458+
1459+ if (is_click(appid)) {
1460+ gchar * appfile = g_strdup_printf("application-click-%s.log", appid);
1461+ path = g_build_filename(g_get_user_cache_dir(), "upstart", appfile, NULL);
1462+ g_free(appfile);
1463+ return path;
1464+ }
1465+
1466+ if (legacy_single_instance(appid)) {
1467+ gchar * appfile = g_strdup_printf("application-legacy-%s-.log", appid);
1468+ path = g_build_filename(g_get_user_cache_dir(), "upstart", appfile, NULL);
1469+ g_free(appfile);
1470+ return path;
1471+ }
1472+
1473+ /* If we're not single instance, we can't recreate the instance ID
1474+ but if it's running we can grab it. */
1475+ unsigned int i;
1476+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
1477+ g_return_val_if_fail(con != NULL, NULL);
1478+
1479+ GArray * apps = g_array_new(TRUE, TRUE, sizeof(gchar *));
1480+ g_array_set_clear_func(apps, free_helper);
1481+
1482+ apps_for_job(con, "application-legacy", apps, FALSE);
1483+ gchar * appiddash = g_strdup_printf("%s-", appid); /* Probably could go RegEx here, but let's start with just a prefix lookup */
1484+ for (i = 0; i < apps->len && path == NULL; i++) {
1485+ const gchar * array_id = g_array_index(apps, const gchar *, i);
1486+ if (g_str_has_prefix(array_id, appiddash)) {
1487+ gchar * appfile = g_strdup_printf("application-legacy-%s.log", array_id);
1488+ path = g_build_filename(g_get_user_cache_dir(), "upstart", appfile, NULL);
1489+ g_free(appfile);
1490+ }
1491+ }
1492+ g_free(appiddash);
1493+
1494+ g_array_free(apps, TRUE);
1495+ g_object_unref(con);
1496+
1497+ return path;
1498+}
1499+
1500 static GDBusConnection *
1501 gdbus_upstart_ref (void) {
1502 static GDBusConnection * gdbus_upstart = NULL;
1503@@ -523,164 +709,210 @@
1504 return FALSE;
1505 }
1506
1507+typedef void (*per_instance_func_t) (GDBusConnection * con, GVariant * prop_dict, gpointer user_data);
1508+
1509+static void
1510+foreach_job_instance (GDBusConnection * con, const gchar * jobname, per_instance_func_t func, gpointer user_data)
1511+{
1512+ const gchar * job_path = get_jobpath(con, jobname);
1513+ if (job_path == NULL)
1514+ return;
1515+
1516+ GError * error = NULL;
1517+ GVariant * instance_tuple = g_dbus_connection_call_sync(con,
1518+ DBUS_SERVICE_UPSTART,
1519+ job_path,
1520+ DBUS_INTERFACE_UPSTART_JOB,
1521+ "GetAllInstances",
1522+ NULL,
1523+ G_VARIANT_TYPE("(ao)"),
1524+ G_DBUS_CALL_FLAGS_NONE,
1525+ -1, /* timeout: default */
1526+ NULL, /* cancelable */
1527+ &error);
1528+
1529+ if (error != NULL) {
1530+ g_warning("Unable to get instances of job '%s': %s", jobname, error->message);
1531+ g_error_free(error);
1532+ return;
1533+ }
1534+
1535+ GVariant * instance_list = g_variant_get_child_value(instance_tuple, 0);
1536+ g_variant_unref(instance_tuple);
1537+
1538+ GVariantIter instance_iter;
1539+ g_variant_iter_init(&instance_iter, instance_list);
1540+ const gchar * instance_path = NULL;
1541+
1542+ while (g_variant_iter_loop(&instance_iter, "&o", &instance_path)) {
1543+ GVariant * props_tuple = g_dbus_connection_call_sync(con,
1544+ DBUS_SERVICE_UPSTART,
1545+ instance_path,
1546+ "org.freedesktop.DBus.Properties",
1547+ "GetAll",
1548+ g_variant_new("(s)", DBUS_INTERFACE_UPSTART_INSTANCE),
1549+ G_VARIANT_TYPE("(a{sv})"),
1550+ G_DBUS_CALL_FLAGS_NONE,
1551+ -1, /* timeout: default */
1552+ NULL, /* cancelable */
1553+ &error);
1554+
1555+ if (error != NULL) {
1556+ g_warning("Unable to name of instance '%s': %s", instance_path, error->message);
1557+ g_error_free(error);
1558+ error = NULL;
1559+ continue;
1560+ }
1561+
1562+ GVariant * props_dict = g_variant_get_child_value(props_tuple, 0);
1563+
1564+ func(con, props_dict, user_data);
1565+
1566+ g_variant_unref(props_dict);
1567+ g_variant_unref(props_tuple);
1568+
1569+ }
1570+
1571+ g_variant_unref(instance_list);
1572+}
1573+
1574+typedef struct {
1575+ GArray * apps;
1576+ gboolean truncate_legacy;
1577+ const gchar * jobname;
1578+} apps_for_job_t;
1579+
1580+static void
1581+apps_for_job_instance (GDBusConnection * con, GVariant * props_dict, gpointer user_data)
1582+{
1583+ GVariant * namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
1584+ if (namev == NULL) {
1585+ return;
1586+ }
1587+
1588+ apps_for_job_t * data = (apps_for_job_t *)user_data;
1589+ gchar * instance_name = g_variant_dup_string(namev, NULL);
1590+ g_variant_unref(namev);
1591+
1592+ if (data->truncate_legacy && g_strcmp0(data->jobname, "application-legacy") == 0) {
1593+ gchar * last_dash = g_strrstr(instance_name, "-");
1594+ if (last_dash != NULL) {
1595+ last_dash[0] = '\0';
1596+ }
1597+ }
1598+
1599+ g_array_append_val(data->apps, instance_name);
1600+}
1601+
1602 /* Get all the instances for a given job name */
1603 static void
1604-apps_for_job (NihDBusProxy * upstart, const gchar * name, GArray * apps, gboolean truncate_legacy)
1605+apps_for_job (GDBusConnection * con, const gchar * jobname, GArray * apps, gboolean truncate_legacy)
1606 {
1607- nih_local char * job_path = NULL;
1608- if (upstart_get_job_by_name_sync(NULL, upstart, name, &job_path) != 0) {
1609- g_warning("Unable to find job '%s'", name);
1610- return;
1611- }
1612-
1613- nih_local NihDBusProxy * job_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
1614- upstart->name,
1615- job_path,
1616- NULL, NULL);
1617-
1618- if (job_proxy == NULL) {
1619- g_warning("Unable to build proxy to Job '%s'", name);
1620- return;
1621- }
1622-
1623- nih_local char ** instances;
1624- if (job_class_get_all_instances_sync(NULL, job_proxy, &instances) != 0) {
1625- NihError * error = nih_error_get();
1626- g_warning("Unable to get instances for job '%s': %s", name, error->message);
1627- nih_free(error);
1628- return;
1629- }
1630-
1631- int jobnum;
1632- for (jobnum = 0; instances[jobnum] != NULL; jobnum++) {
1633- NihDBusProxy * instance_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
1634- upstart->name,
1635- instances[jobnum],
1636- NULL, NULL);
1637-
1638- nih_local char * instance_name = NULL;
1639- if (job_get_name_sync(NULL, instance_proxy, &instance_name) == 0) {
1640- gchar * dup = g_strdup(instance_name);
1641-
1642- if (truncate_legacy && g_strcmp0(name, "application-legacy") == 0) {
1643- gchar * last_dash = g_strrstr(dup, "-");
1644- if (last_dash != NULL) {
1645- last_dash[0] = '\0';
1646- }
1647- }
1648-
1649- g_array_append_val(apps, dup);
1650- } else {
1651- g_warning("Unable to get name for instance '%s' of job '%s'", instances[jobnum], name);
1652- }
1653-
1654- nih_unref(instance_proxy, NULL);
1655- }
1656+ apps_for_job_t data = {
1657+ .jobname = jobname,
1658+ .apps = apps,
1659+ .truncate_legacy = truncate_legacy
1660+ };
1661+
1662+ foreach_job_instance(con, jobname, apps_for_job_instance, &data);
1663 }
1664
1665 gchar **
1666 upstart_app_launch_list_running_apps (void)
1667 {
1668- NihDBusProxy * proxy = NULL;
1669-
1670- proxy = nih_proxy_create();
1671- if (proxy == NULL) {
1672- return g_new0(gchar *, 1);
1673- }
1674+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
1675+ g_return_val_if_fail(con != NULL, g_new0(gchar *, 1));
1676
1677 GArray * apps = g_array_new(TRUE, TRUE, sizeof(gchar *));
1678
1679- apps_for_job(proxy, "application-legacy", apps, TRUE);
1680- apps_for_job(proxy, "application-click", apps, FALSE);
1681+ apps_for_job(con, "application-legacy", apps, TRUE);
1682+ apps_for_job(con, "application-click", apps, FALSE);
1683
1684- nih_unref(proxy, NULL);
1685+ g_object_unref(con);
1686
1687 return (gchar **)g_array_free(apps, FALSE);
1688 }
1689
1690+typedef struct {
1691+ GPid pid;
1692+ const gchar * appid;
1693+ const gchar * jobname;
1694+} pid_for_job_t;
1695+
1696+static void
1697+pid_for_job_instance (GDBusConnection * con, GVariant * props_dict, gpointer user_data)
1698+{
1699+ GVariant * namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
1700+ if (namev == NULL) {
1701+ return;
1702+ }
1703+
1704+ pid_for_job_t * data = (pid_for_job_t *)user_data;
1705+ gchar * instance_name = g_variant_dup_string(namev, NULL);
1706+ g_variant_unref(namev);
1707+
1708+ if (g_strcmp0(data->jobname, "application-legacy") == 0) {
1709+ gchar * last_dash = g_strrstr(instance_name, "-");
1710+ if (last_dash != NULL) {
1711+ last_dash[0] = '\0';
1712+ }
1713+ }
1714+
1715+ if (g_strcmp0(instance_name, data->appid) == 0) {
1716+ GVariant * processv = g_variant_lookup_value(props_dict, "processes", G_VARIANT_TYPE("a(si)"));
1717+
1718+ if (processv != NULL) {
1719+ if (g_variant_n_children(processv) > 0) {
1720+ GVariant * first_entry = g_variant_get_child_value(processv, 0);
1721+ GVariant * pidv = g_variant_get_child_value(first_entry, 1);
1722+
1723+ data->pid = g_variant_get_int32(pidv);
1724+
1725+ g_variant_unref(pidv);
1726+ g_variant_unref(first_entry);
1727+ }
1728+
1729+ g_variant_unref(processv);
1730+ }
1731+ }
1732+
1733+ g_free(instance_name);
1734+}
1735+
1736 /* Look for the app for a job */
1737 static GPid
1738-pid_for_job (NihDBusProxy * upstart, const gchar * job, const gchar * appid)
1739+pid_for_job (GDBusConnection * con, const gchar * jobname, const gchar * appid)
1740 {
1741- nih_local char * job_path = NULL;
1742- if (upstart_get_job_by_name_sync(NULL, upstart, job, &job_path) != 0) {
1743- g_warning("Unable to find job '%s'", job);
1744- return 0;
1745- }
1746-
1747- NihDBusProxy * job_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
1748- upstart->name,
1749- job_path,
1750- NULL, NULL);
1751-
1752- if (job_proxy == NULL) {
1753- g_warning("Unable to build proxy to Job '%s'", job);
1754- return 0;
1755- }
1756-
1757- nih_local char ** instances;
1758- if (job_class_get_all_instances_sync(NULL, job_proxy, &instances) != 0) {
1759- g_warning("Unable to get instances for job '%s'", job);
1760- nih_unref(job_proxy, NULL);
1761- return 0;
1762- }
1763-
1764- GPid pid = 0;
1765- int jobnum;
1766- for (jobnum = 0; instances[jobnum] != NULL && pid == 0; jobnum++) {
1767- NihDBusProxy * instance_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
1768- upstart->name,
1769- instances[jobnum],
1770- NULL, NULL);
1771-
1772- nih_local char * instance_name = NULL;
1773- if (job_get_name_sync(NULL, instance_proxy, &instance_name) == 0) {
1774- if (g_strcmp0(job, "application-legacy") == 0) {
1775- gchar * last_dash = g_strrstr(instance_name, "-");
1776- if (last_dash != NULL) {
1777- last_dash[0] = '\0';
1778- }
1779- }
1780- } else {
1781- g_warning("Unable to get name for instance '%s' of job '%s'", instances[jobnum], job);
1782- }
1783-
1784- if (g_strcmp0(instance_name, appid) == 0) {
1785- nih_local JobProcessesElement ** elements;
1786- if (job_get_processes_sync(NULL, instance_proxy, &elements) == 0) {
1787- pid = elements[0]->item1;
1788- }
1789- }
1790-
1791- nih_unref(instance_proxy, NULL);
1792- }
1793-
1794- nih_unref(job_proxy, NULL);
1795-
1796- return pid;
1797+ pid_for_job_t data = {
1798+ .jobname = jobname,
1799+ .appid = appid,
1800+ .pid = 0
1801+ };
1802+
1803+ foreach_job_instance(con, jobname, pid_for_job_instance, &data);
1804+
1805+ return data.pid;
1806 }
1807
1808 GPid
1809 upstart_app_launch_get_primary_pid (const gchar * appid)
1810 {
1811- NihDBusProxy * proxy = NULL;
1812+ g_return_val_if_fail(appid != NULL, 0);
1813
1814- proxy = nih_proxy_create();
1815- if (proxy == NULL) {
1816- return 0;
1817- }
1818+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
1819+ g_return_val_if_fail(con != NULL, 0);
1820
1821 GPid pid = 0;
1822
1823 if (pid == 0) {
1824- pid = pid_for_job(proxy, "application-legacy", appid);
1825+ pid = pid_for_job(con, "application-legacy", appid);
1826 }
1827
1828 if (pid == 0) {
1829- pid = pid_for_job(proxy, "application-click", appid);
1830+ pid = pid_for_job(con, "application-click", appid);
1831 }
1832
1833- nih_unref(proxy, NULL);
1834+ g_object_unref(con);
1835
1836 return pid;
1837 }
1838@@ -688,6 +920,8 @@
1839 gboolean
1840 upstart_app_launch_pid_in_app_id (GPid pid, const gchar * appid)
1841 {
1842+ g_return_val_if_fail(appid != NULL, FALSE);
1843+
1844 if (pid == 0) {
1845 return FALSE;
1846 }
1847
1848=== modified file 'libupstart-app-launch/upstart-app-launch.h'
1849--- libupstart-app-launch/upstart-app-launch.h 2014-01-29 02:33:52 +0000
1850+++ libupstart-app-launch/upstart-app-launch.h 2014-02-06 18:42:36 +0000
1851@@ -80,6 +80,19 @@
1852 gboolean upstart_app_launch_stop_application (const gchar * appid);
1853
1854 /**
1855+ * upstart_app_launch_application_log_path:
1856+ * @appid: ID of the application
1857+ *
1858+ * Calculates the path for the log file that may be generated by
1859+ * the application. The log file won't be created until the application
1860+ * prints some output. Also, this doens't work for legacy applications
1861+ * that are multi-instance, only single instance ones.
1862+ *
1863+ * Return value: Path to a log file or NULL if unavailable
1864+ */
1865+gchar * upstart_app_launch_application_log_path (const gchar * appid);
1866+
1867+/**
1868 * upstart_app_launch_observer_add_app_starting:
1869 * @observer: Callback when an application is about to start
1870 * @user_data: (allow none): Data to pass to the observer
1871
1872=== removed file 'second-exec-trace.tp'
1873--- second-exec-trace.tp 2013-12-04 17:32:23 +0000
1874+++ second-exec-trace.tp 1970-01-01 00:00:00 +0000
1875@@ -1,16 +0,0 @@
1876-
1877-TRACEPOINT_EVENT(upstart_app_launch, second_exec_start, TP_ARGS(0), TP_FIELDS())
1878-TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_resume, TP_ARGS(0), TP_FIELDS())
1879-TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_complete, TP_ARGS(0), TP_FIELDS())
1880-TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_timeout, TP_ARGS(0), TP_FIELDS())
1881-TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_focus, TP_ARGS(0), TP_FIELDS())
1882-TRACEPOINT_EVENT(upstart_app_launch, second_exec_finish, TP_ARGS(0), TP_FIELDS())
1883-TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_dbus_names, TP_ARGS(0), TP_FIELDS())
1884-TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_primary_pid, TP_ARGS(0), TP_FIELDS())
1885-TRACEPOINT_EVENT(upstart_app_launch, second_exec_request_pid, TP_ARGS(0), TP_FIELDS())
1886-TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_pid, TP_ARGS(0), TP_FIELDS())
1887-TRACEPOINT_EVENT(upstart_app_launch, second_exec_contact_app, TP_ARGS(0), TP_FIELDS())
1888-TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_contacted, TP_ARGS(0), TP_FIELDS())
1889-TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_error, TP_ARGS(0), TP_FIELDS())
1890-TRACEPOINT_EVENT(upstart_app_launch, second_exec_connection_complete, TP_ARGS(0), TP_FIELDS())
1891-
1892
1893=== removed file 'second-exec.c'
1894--- second-exec.c 2013-12-05 17:08:13 +0000
1895+++ second-exec.c 1970-01-01 00:00:00 +0000
1896@@ -1,40 +0,0 @@
1897-/*
1898- * Copyright 2013 Canonical Ltd.
1899- *
1900- * This program is free software: you can redistribute it and/or modify it
1901- * under the terms of the GNU General Public License version 3, as published
1902- * by the Free Software Foundation.
1903- *
1904- * This program is distributed in the hope that it will be useful, but
1905- * WITHOUT ANY WARRANTY; without even the implied warranties of
1906- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1907- * PURPOSE. See the GNU General Public License for more details.
1908- *
1909- * You should have received a copy of the GNU General Public License along
1910- * with this program. If not, see <http://www.gnu.org/licenses/>.
1911- *
1912- * Authors:
1913- * Ted Gould <ted.gould@canonical.com>
1914- */
1915-
1916-#include "second-exec-core.h"
1917-
1918-int
1919-main (int argc, char * argv[])
1920-{
1921- if (argc != 1) {
1922- g_error("Should be called as: %s", argv[0]);
1923- return 1;
1924- }
1925-
1926- const gchar * appid = g_getenv("APP_ID");
1927- const gchar * appuris = g_getenv("APP_URIS");
1928-
1929- g_setenv("LTTNG_UST_REGISTER_TIMEOUT", "0", FALSE); /* Set to zero if not set */
1930-
1931- if (second_exec(appid, appuris)) {
1932- return 0;
1933- } else {
1934- return 1;
1935- }
1936-}
1937
1938=== modified file 'tests/CMakeLists.txt'
1939--- tests/CMakeLists.txt 2014-01-13 15:16:24 +0000
1940+++ tests/CMakeLists.txt 2014-02-06 18:42:36 +0000
1941@@ -25,16 +25,6 @@
1942
1943 add_test (helper-handshake-test helper-handshake-test)
1944
1945-# Second Exec Test
1946-
1947-include_directories("${CMAKE_SOURCE_DIR}/libupstart-app-launch")
1948-
1949-add_executable (second-exec-test
1950- second-exec-test.cc
1951- upstart-app-launch-mock.c)
1952-target_link_libraries (second-exec-test helpers gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} upstart-launcher second-exec-core)
1953-add_test (second-exec-test second-exec-test)
1954-
1955 # libUAL Test
1956
1957 include_directories("${CMAKE_SOURCE_DIR}/libupstart-app-launch")
1958@@ -43,14 +33,7 @@
1959 libual-test.cc)
1960 target_link_libraries (libual-test helpers gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} upstart-launcher)
1961
1962-# NOTE: Tests are broken into individual runs to avoid problems with libdbus
1963-add_test (NAME libual-test-start COMMAND libual-test --gtest_filter=*StartApplication)
1964-add_test (NAME libual-test-stop COMMAND libual-test --gtest_filter=*StopApplication)
1965-add_test (NAME libual-test-pid COMMAND libual-test --gtest_filter=*ApplicationPid)
1966-add_test (NAME libual-test-app-id COMMAND libual-test --gtest_filter=*ApplicationId)
1967-add_test (NAME libual-test-list COMMAND libual-test --gtest_filter=*ApplicationList)
1968-add_test (NAME libual-test-observer COMMAND libual-test --gtest_filter=*StartStopObserver)
1969-add_test (NAME libual-test-starting COMMAND libual-test --gtest_filter=*StartingResponses)
1970+add_test (NAME libual-test COMMAND libual-test)
1971
1972 # ZG Test
1973
1974
1975=== added file 'tests/applications/multiple.desktop'
1976--- tests/applications/multiple.desktop 1970-01-01 00:00:00 +0000
1977+++ tests/applications/multiple.desktop 2014-02-06 18:42:36 +0000
1978@@ -0,0 +1,8 @@
1979+[Desktop Entry]
1980+Name=Multiple
1981+Type=Application
1982+Exec=multiple
1983+NoDisplay=false
1984+Hidden=false
1985+Terminal=false
1986+X-Ubuntu-Single-Instance=false
1987
1988=== added file 'tests/applications/single.desktop'
1989--- tests/applications/single.desktop 1970-01-01 00:00:00 +0000
1990+++ tests/applications/single.desktop 2014-02-06 18:42:36 +0000
1991@@ -0,0 +1,8 @@
1992+[Desktop Entry]
1993+Name=Single
1994+Type=Application
1995+Exec=single
1996+NoDisplay=false
1997+Hidden=false
1998+Terminal=false
1999+X-Ubuntu-Single-Instance=true
2000
2001=== modified file 'tests/libual-test.cc'
2002--- tests/libual-test.cc 2014-01-29 02:24:06 +0000
2003+++ tests/libual-test.cc 2014-02-06 18:42:36 +0000
2004@@ -31,6 +31,26 @@
2005 DbusTestService * service = NULL;
2006 DbusTestDbusMock * mock = NULL;
2007 GDBusConnection * bus = NULL;
2008+ std::string last_focus_appid;
2009+ std::string last_resume_appid;
2010+ guint resume_timeout = 0;
2011+
2012+ private:
2013+ static void focus_cb (const gchar * appid, gpointer user_data) {
2014+ g_debug("Focus Callback: %s", appid);
2015+ LibUAL * _this = static_cast<LibUAL *>(user_data);
2016+ _this->last_focus_appid = appid;
2017+ }
2018+
2019+ static void resume_cb (const gchar * appid, gpointer user_data) {
2020+ g_debug("Resume Callback: %s", appid);
2021+ LibUAL * _this = static_cast<LibUAL *>(user_data);
2022+ _this->last_resume_appid = appid;
2023+
2024+ if (_this->resume_timeout > 0) {
2025+ _this->pause(_this->resume_timeout);
2026+ }
2027+ }
2028
2029 protected:
2030 /* Useful debugging stuff, but not on by default. You really want to
2031@@ -48,8 +68,15 @@
2032 }
2033
2034 virtual void SetUp() {
2035+ gchar * linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL);
2036+ g_setenv("UPSTART_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE);
2037+ g_free(linkfarmpath);
2038+
2039+ g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
2040+ g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR, TRUE);
2041+
2042 service = dbus_test_service_new(NULL);
2043- g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
2044+
2045 const gchar * oldpath = g_getenv("PATH");
2046 gchar * newpath = g_strjoin(":", CMAKE_SOURCE_DIR, oldpath, NULL);
2047 g_setenv("PATH", newpath, TRUE);
2048@@ -81,6 +108,14 @@
2049 DbusTestDbusMockObject * jobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
2050
2051 dbus_test_dbus_mock_object_add_method(mock, jobobj,
2052+ "Start",
2053+ G_VARIANT_TYPE("(asb)"),
2054+ NULL,
2055+ "if args[0][0] == 'APP_ID=foo':"
2056+ " raise dbus.exceptions.DBusException('Foo running', name='com.ubuntu.Upstart0_6.Error.AlreadyStarted')",
2057+ NULL);
2058+
2059+ dbus_test_dbus_mock_object_add_method(mock, jobobj,
2060 "Stop",
2061 G_VARIANT_TYPE("(asb)"),
2062 NULL,
2063@@ -100,15 +135,24 @@
2064 G_VARIANT_TYPE_STRING,
2065 g_variant_new_string("foo"),
2066 NULL);
2067+ gchar * process_var = g_strdup_printf("[('main', %d)]", getpid());
2068 dbus_test_dbus_mock_object_add_property(mock, instobj,
2069 "processes",
2070 G_VARIANT_TYPE("a(si)"),
2071- g_variant_new_parsed("[('main', 1234)]"),
2072+ g_variant_new_parsed(process_var),
2073 NULL);
2074+ g_free(process_var);
2075
2076 DbusTestDbusMockObject * ljobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
2077
2078 dbus_test_dbus_mock_object_add_method(mock, ljobobj,
2079+ "Start",
2080+ G_VARIANT_TYPE("(asb)"),
2081+ NULL,
2082+ "",
2083+ NULL);
2084+
2085+ dbus_test_dbus_mock_object_add_method(mock, ljobobj,
2086 "Stop",
2087 G_VARIANT_TYPE("(asb)"),
2088 NULL,
2089@@ -140,9 +184,15 @@
2090 bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2091 g_dbus_connection_set_exit_on_close(bus, FALSE);
2092 g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);
2093+
2094+ ASSERT_TRUE(upstart_app_launch_observer_add_app_focus(focus_cb, this));
2095+ ASSERT_TRUE(upstart_app_launch_observer_add_app_resume(resume_cb, this));
2096 }
2097
2098 virtual void TearDown() {
2099+ upstart_app_launch_observer_delete_app_focus(focus_cb, this);
2100+ upstart_app_launch_observer_delete_app_resume(resume_cb, this);
2101+
2102 g_clear_object(&mock);
2103 g_clear_object(&service);
2104
2105@@ -150,12 +200,10 @@
2106
2107 unsigned int cleartry = 0;
2108 while (bus != NULL && cleartry < 100) {
2109- g_usleep(100000);
2110- while (g_main_pending()) {
2111- g_main_iteration(TRUE);
2112- }
2113+ pause(100);
2114 cleartry++;
2115 }
2116+ ASSERT_EQ(bus, nullptr);
2117 }
2118
2119 bool check_env (GVariant * env_array, const gchar * var, const gchar * value) {
2120@@ -189,18 +237,17 @@
2121 }
2122
2123 static gboolean pause_helper (gpointer pmainloop) {
2124- g_main_loop_quit((GMainLoop *)pmainloop);
2125+ g_main_loop_quit(static_cast<GMainLoop *>(pmainloop));
2126 return G_SOURCE_REMOVE;
2127 }
2128
2129 void pause (guint time) {
2130 if (time > 0) {
2131 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
2132- guint timer = g_timeout_add(time, pause_helper, mainloop);
2133+ g_timeout_add(time, pause_helper, mainloop);
2134
2135 g_main_loop_run(mainloop);
2136
2137- g_source_remove(timer);
2138 g_main_loop_unref(mainloop);
2139 }
2140
2141@@ -212,35 +259,31 @@
2142
2143 TEST_F(LibUAL, StartApplication)
2144 {
2145- DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
2146+ DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
2147
2148 /* Basic make sure we can send the event */
2149- ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
2150- ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "EmitEvent", NULL, NULL), 1);
2151+ ASSERT_TRUE(upstart_app_launch_start_application("foolike", NULL));
2152+ EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
2153
2154 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
2155
2156 /* Now look at the details of the call */
2157- ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
2158+ ASSERT_TRUE(upstart_app_launch_start_application("foolike", NULL));
2159
2160 guint len = 0;
2161- const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "EmitEvent", &len, NULL);
2162- ASSERT_NE(calls, nullptr);
2163- ASSERT_EQ(len, 1);
2164-
2165- ASSERT_STREQ(calls->name, "EmitEvent");
2166- ASSERT_EQ(g_variant_n_children(calls->params), 3);
2167-
2168- GVariant * name = g_variant_get_child_value(calls->params, 0);
2169- ASSERT_STREQ(g_variant_get_string(name, NULL), "application-start");
2170- g_variant_unref(name);
2171-
2172- GVariant * block = g_variant_get_child_value(calls->params, 2);
2173- ASSERT_FALSE(g_variant_get_boolean(block));
2174+ const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
2175+ EXPECT_NE(nullptr, calls);
2176+ EXPECT_EQ(1, len);
2177+
2178+ EXPECT_STREQ("Start", calls->name);
2179+ EXPECT_EQ(2, g_variant_n_children(calls->params));
2180+
2181+ GVariant * block = g_variant_get_child_value(calls->params, 1);
2182+ EXPECT_TRUE(g_variant_get_boolean(block));
2183 g_variant_unref(block);
2184
2185- GVariant * env = g_variant_get_child_value(calls->params, 1);
2186- ASSERT_TRUE(check_env(env, "APP_ID", "foo"));
2187+ GVariant * env = g_variant_get_child_value(calls->params, 0);
2188+ EXPECT_TRUE(check_env(env, "APP_ID", "foolike"));
2189 g_variant_unref(env);
2190
2191 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
2192@@ -252,16 +295,16 @@
2193 "file:///home/phablet/test.txt",
2194 NULL
2195 };
2196- ASSERT_TRUE(upstart_app_launch_start_application("foo", urls));
2197+ ASSERT_TRUE(upstart_app_launch_start_application("foolike", urls));
2198
2199 len = 0;
2200- calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "EmitEvent", &len, NULL);
2201- ASSERT_NE(calls, nullptr);
2202- ASSERT_EQ(len, 1);
2203+ calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
2204+ EXPECT_NE(nullptr, calls);
2205+ EXPECT_EQ(1, len);
2206
2207- env = g_variant_get_child_value(calls->params, 1);
2208- ASSERT_TRUE(check_env(env, "APP_ID", "foo"));
2209- ASSERT_TRUE(check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
2210+ env = g_variant_get_child_value(calls->params, 0);
2211+ EXPECT_TRUE(check_env(env, "APP_ID", "foolike"));
2212+ EXPECT_TRUE(check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
2213 g_variant_unref(env);
2214
2215 return;
2216@@ -277,12 +320,27 @@
2217
2218 }
2219
2220+TEST_F(LibUAL, ApplicationLog)
2221+{
2222+ gchar * click_log = upstart_app_launch_application_log_path("foo");
2223+ EXPECT_STREQ(CMAKE_SOURCE_DIR "/upstart/application-click-foo.log", click_log);
2224+ g_free(click_log);
2225+
2226+ gchar * legacy_single = upstart_app_launch_application_log_path("single");
2227+ EXPECT_STREQ(CMAKE_SOURCE_DIR "/upstart/application-legacy-single-.log", legacy_single);
2228+ g_free(legacy_single);
2229+
2230+ gchar * legacy_multiple = upstart_app_launch_application_log_path("bar");
2231+ EXPECT_STREQ(CMAKE_SOURCE_DIR "/upstart/application-legacy-bar-2342345.log", legacy_multiple);
2232+ g_free(legacy_multiple);
2233+}
2234+
2235 TEST_F(LibUAL, ApplicationPid)
2236 {
2237- ASSERT_EQ(upstart_app_launch_get_primary_pid("foo"), 1234);
2238- ASSERT_EQ(upstart_app_launch_get_primary_pid("bar"), 5678);
2239- ASSERT_TRUE(upstart_app_launch_pid_in_app_id(1234, "foo"));
2240- ASSERT_FALSE(upstart_app_launch_pid_in_app_id(5678, "foo"));
2241+ EXPECT_EQ(upstart_app_launch_get_primary_pid("foo"), getpid());
2242+ EXPECT_EQ(upstart_app_launch_get_primary_pid("bar"), 5678);
2243+ EXPECT_TRUE(upstart_app_launch_pid_in_app_id(getpid(), "foo"));
2244+ EXPECT_FALSE(upstart_app_launch_pid_in_app_id(5678, "foo"));
2245 }
2246
2247 TEST_F(LibUAL, ApplicationId)
2248@@ -527,3 +585,178 @@
2249 g_dbus_connection_remove_filter(session, filter);
2250 g_object_unref(session);
2251 }
2252+
2253+TEST_F(LibUAL, AppIdTest)
2254+{
2255+ ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
2256+ pause(50); /* Ensure all the events come through */
2257+ EXPECT_EQ("foo", this->last_focus_appid);
2258+ EXPECT_EQ("foo", this->last_resume_appid);
2259+}
2260+
2261+GDBusMessage *
2262+filter_func_good (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
2263+{
2264+ if (!incomming) {
2265+ return message;
2266+ }
2267+
2268+ if (g_strcmp0(g_dbus_message_get_path(message), (gchar *)user_data) == 0) {
2269+ GDBusMessage * reply = g_dbus_message_new_method_reply(message);
2270+ g_dbus_connection_send_message(conn, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
2271+ g_object_unref(message);
2272+ return NULL;
2273+ }
2274+
2275+ return message;
2276+}
2277+
2278+TEST_F(LibUAL, UrlSendTest)
2279+{
2280+ GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2281+ guint filter = g_dbus_connection_add_filter(session,
2282+ filter_func_good,
2283+ (gpointer)"/foo",
2284+ NULL);
2285+
2286+ const gchar * uris[] = {
2287+ "http://www.test.com",
2288+ NULL
2289+ };
2290+ ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
2291+ pause(100); /* Ensure all the events come through */
2292+
2293+ EXPECT_EQ("foo", this->last_focus_appid);
2294+ EXPECT_EQ("foo", this->last_resume_appid);
2295+
2296+ g_dbus_connection_remove_filter(session, filter);
2297+ g_object_unref(session);
2298+}
2299+
2300+TEST_F(LibUAL, UrlSendNoObjectTest)
2301+{
2302+ const gchar * uris[] = {
2303+ "http://www.test.com",
2304+ NULL
2305+ };
2306+
2307+ ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
2308+ pause(100); /* Ensure all the events come through */
2309+
2310+ EXPECT_EQ("foo", this->last_focus_appid);
2311+ EXPECT_EQ("foo", this->last_resume_appid);
2312+}
2313+
2314+TEST_F(LibUAL, UnityTimeoutTest)
2315+{
2316+ this->resume_timeout = 100;
2317+
2318+ ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
2319+ pause(1000); /* Ensure all the events come through */
2320+ EXPECT_EQ("foo", this->last_focus_appid);
2321+ EXPECT_EQ("foo", this->last_resume_appid);
2322+}
2323+
2324+TEST_F(LibUAL, UnityTimeoutUriTest)
2325+{
2326+ this->resume_timeout = 200;
2327+
2328+ const gchar * uris[] = {
2329+ "http://www.test.com",
2330+ NULL
2331+ };
2332+
2333+ ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
2334+ pause(1000); /* Ensure all the events come through */
2335+ EXPECT_EQ("foo", this->last_focus_appid);
2336+ EXPECT_EQ("foo", this->last_resume_appid);
2337+}
2338+
2339+GDBusMessage *
2340+filter_respawn (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
2341+{
2342+ if (g_strcmp0(g_dbus_message_get_member(message), "UnityResumeResponse") == 0) {
2343+ g_object_unref(message);
2344+ return NULL;
2345+ }
2346+
2347+ return message;
2348+}
2349+
2350+TEST_F(LibUAL, UnityLostTest)
2351+{
2352+ GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2353+ guint filter = g_dbus_connection_add_filter(session,
2354+ filter_respawn,
2355+ NULL,
2356+ NULL);
2357+
2358+ guint start = g_get_monotonic_time();
2359+
2360+ const gchar * uris[] = {
2361+ "http://www.test.com",
2362+ NULL
2363+ };
2364+
2365+ ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
2366+
2367+ guint end = g_get_monotonic_time();
2368+
2369+ EXPECT_LT(end - start, 600 * 1000);
2370+
2371+ pause(1000); /* Ensure all the events come through */
2372+
2373+ EXPECT_EQ("foo", this->last_focus_appid);
2374+ EXPECT_EQ("foo", this->last_resume_appid);
2375+
2376+ g_dbus_connection_remove_filter(session, filter);
2377+ g_object_unref(session);
2378+}
2379+
2380+
2381+TEST_F(LibUAL, LegacySingleInstance)
2382+{
2383+ DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
2384+
2385+ /* Check for a single-instance app */
2386+ ASSERT_TRUE(upstart_app_launch_start_application("single", NULL));
2387+
2388+ guint len = 0;
2389+ const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
2390+ EXPECT_NE(nullptr, calls);
2391+ EXPECT_EQ(1, len);
2392+
2393+ EXPECT_STREQ("Start", calls->name);
2394+ EXPECT_EQ(2, g_variant_n_children(calls->params));
2395+
2396+ GVariant * block = g_variant_get_child_value(calls->params, 1);
2397+ EXPECT_TRUE(g_variant_get_boolean(block));
2398+ g_variant_unref(block);
2399+
2400+ GVariant * env = g_variant_get_child_value(calls->params, 0);
2401+ EXPECT_TRUE(check_env(env, "APP_ID", "single"));
2402+ EXPECT_TRUE(check_env(env, "INSTANCE_ID", ""));
2403+ g_variant_unref(env);
2404+
2405+ ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
2406+
2407+ /* Check for a multi-instance app */
2408+ ASSERT_TRUE(upstart_app_launch_start_application("multiple", NULL));
2409+
2410+ len = 0;
2411+ calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
2412+ EXPECT_NE(nullptr, calls);
2413+ EXPECT_EQ(1, len);
2414+
2415+ EXPECT_STREQ("Start", calls->name);
2416+ EXPECT_EQ(2, g_variant_n_children(calls->params));
2417+
2418+ block = g_variant_get_child_value(calls->params, 1);
2419+ EXPECT_TRUE(g_variant_get_boolean(block));
2420+ g_variant_unref(block);
2421+
2422+ env = g_variant_get_child_value(calls->params, 0);
2423+ EXPECT_TRUE(check_env(env, "APP_ID", "multiple"));
2424+ EXPECT_FALSE(check_env(env, "INSTANCE_ID", ""));
2425+ g_variant_unref(env);
2426+}
2427
2428=== added directory 'tests/link-farm'
2429=== added file 'tests/link-farm/README'
2430--- tests/link-farm/README 1970-01-01 00:00:00 +0000
2431+++ tests/link-farm/README 2014-02-06 18:42:36 +0000
2432@@ -0,0 +1,3 @@
2433+This directory is setup as our testing link farm. Anything that has a
2434+desktop in here will be detected as a click package, something without
2435+will be seen as a legacy package.
2436
2437=== added file 'tests/link-farm/foo.desktop'
2438--- tests/link-farm/foo.desktop 1970-01-01 00:00:00 +0000
2439+++ tests/link-farm/foo.desktop 2014-02-06 18:42:36 +0000
2440@@ -0,0 +1,1 @@
2441+Needs to exist
2442
2443=== added file 'tests/link-farm/foolike.desktop'
2444--- tests/link-farm/foolike.desktop 1970-01-01 00:00:00 +0000
2445+++ tests/link-farm/foolike.desktop 2014-02-06 18:42:36 +0000
2446@@ -0,0 +1,1 @@
2447+Needs to exist
2448
2449=== removed file 'tests/second-exec-test.cc'
2450--- tests/second-exec-test.cc 2013-12-06 11:44:25 +0000
2451+++ tests/second-exec-test.cc 1970-01-01 00:00:00 +0000
2452@@ -1,205 +0,0 @@
2453-/*
2454- * Copyright 2013 Canonical Ltd.
2455- *
2456- * This program is free software: you can redistribute it and/or modify it
2457- * under the terms of the GNU General Public License version 3, as published
2458- * by the Free Software Foundation.
2459- *
2460- * This program is distributed in the hope that it will be useful, but
2461- * WITHOUT ANY WARRANTY; without even the implied warranties of
2462- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2463- * PURPOSE. See the GNU General Public License for more details.
2464- *
2465- * You should have received a copy of the GNU General Public License along
2466- * with this program. If not, see <http://www.gnu.org/licenses/>.
2467- *
2468- * Authors:
2469- * Ted Gould <ted.gould@canonical.com>
2470- */
2471-
2472-#include <gtest/gtest.h>
2473-#include <gio/gio.h>
2474-
2475-extern "C" {
2476-#include "../second-exec-core.h"
2477-#include "upstart-app-launch.h"
2478-#include "upstart-app-launch-mock.h"
2479-}
2480-
2481-class SecondExecTest : public ::testing::Test
2482-{
2483- private:
2484- GTestDBus * testbus = NULL;
2485-
2486- protected:
2487- std::string last_focus_appid;
2488- std::string last_resume_appid;
2489- guint resume_timeout = 0;
2490-
2491- private:
2492- static void focus_cb (const gchar * appid, gpointer user_data) {
2493- SecondExecTest * _this = static_cast<SecondExecTest *>(user_data);
2494- _this->last_focus_appid = appid;
2495- }
2496-
2497- static void resume_cb (const gchar * appid, gpointer user_data) {
2498- SecondExecTest * _this = static_cast<SecondExecTest *>(user_data);
2499- _this->last_resume_appid = appid;
2500-
2501- if (_this->resume_timeout > 0) {
2502- _this->pause(_this->resume_timeout);
2503- }
2504- }
2505-
2506- protected:
2507- virtual void SetUp() {
2508- testbus = g_test_dbus_new(G_TEST_DBUS_NONE);
2509- g_test_dbus_up(testbus);
2510-
2511- upstart_app_launch_observer_add_app_focus(focus_cb, this);
2512- upstart_app_launch_observer_add_app_resume(resume_cb, this);
2513- }
2514- virtual void TearDown() {
2515- upstart_app_launch_observer_delete_app_focus(focus_cb, this);
2516- upstart_app_launch_observer_delete_app_resume(resume_cb, this);
2517-
2518- g_test_dbus_down(testbus);
2519- g_object_unref(testbus);
2520- }
2521-
2522- static gboolean pause_helper (gpointer pmainloop) {
2523- g_main_loop_quit((GMainLoop *)pmainloop);
2524- return G_SOURCE_REMOVE;
2525- }
2526-
2527- void pause (guint time) {
2528- if (time > 0) {
2529- GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
2530- guint timer = g_timeout_add(time, pause_helper, mainloop);
2531-
2532- g_main_loop_run(mainloop);
2533-
2534- g_source_remove(timer);
2535- g_main_loop_unref(mainloop);
2536- }
2537-
2538- while (g_main_pending()) {
2539- g_main_iteration(TRUE);
2540- }
2541- }
2542-};
2543-
2544-TEST_F(SecondExecTest, AppIdTest)
2545-{
2546- ASSERT_TRUE(second_exec("foo", NULL));
2547- pause(50); /* Ensure all the events come through */
2548- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
2549- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
2550-}
2551-
2552-GDBusMessage *
2553-filter_func_good (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
2554-{
2555- if (!incomming) {
2556- return message;
2557- }
2558-
2559- if (g_strcmp0(g_dbus_message_get_path(message), (gchar *)user_data) == 0) {
2560- GDBusMessage * reply = g_dbus_message_new_method_reply(message);
2561- g_dbus_connection_send_message(conn, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
2562- g_object_unref(message);
2563- return NULL;
2564- }
2565-
2566- return message;
2567-}
2568-
2569-TEST_F(SecondExecTest, UrlSendTest)
2570-{
2571- upstart_app_launch_mock_set_primary_pid(getpid());
2572-
2573- GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2574- guint filter = g_dbus_connection_add_filter(session,
2575- filter_func_good,
2576- (gpointer)"/foo",
2577- NULL);
2578-
2579- ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
2580- pause(100); /* Ensure all the events come through */
2581-
2582- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
2583- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
2584-
2585- g_dbus_connection_remove_filter(session, filter);
2586- g_object_unref(session);
2587-}
2588-
2589-TEST_F(SecondExecTest, UrlSendNoObjectTest)
2590-{
2591- upstart_app_launch_mock_set_primary_pid(getpid());
2592-
2593- ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
2594- pause(100); /* Ensure all the events come through */
2595-
2596- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
2597- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
2598-}
2599-
2600-TEST_F(SecondExecTest, UnityTimeoutTest)
2601-{
2602- this->resume_timeout = 100;
2603-
2604- ASSERT_TRUE(second_exec("foo", NULL));
2605- pause(100); /* Ensure all the events come through */
2606- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
2607- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
2608-}
2609-
2610-TEST_F(SecondExecTest, UnityTimeoutUriTest)
2611-{
2612- this->resume_timeout = 200;
2613-
2614- ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
2615- pause(100); /* Ensure all the events come through */
2616- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
2617- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
2618-}
2619-
2620-GDBusMessage *
2621-filter_respawn (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
2622-{
2623- if (g_strcmp0(g_dbus_message_get_member(message), "UnityResumeResponse") == 0) {
2624- g_object_unref(message);
2625- return NULL;
2626- }
2627-
2628- return message;
2629-}
2630-
2631-TEST_F(SecondExecTest, UnityLostTest)
2632-{
2633- upstart_app_launch_mock_set_primary_pid(getpid());
2634-
2635- GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2636- guint filter = g_dbus_connection_add_filter(session,
2637- filter_respawn,
2638- NULL,
2639- NULL);
2640-
2641- guint start = g_get_monotonic_time();
2642-
2643- ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
2644-
2645- guint end = g_get_monotonic_time();
2646-
2647- ASSERT_LT(end - start, 600 * 1000);
2648-
2649- pause(100); /* Ensure all the events come through */
2650- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
2651- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
2652-
2653- g_dbus_connection_remove_filter(session, filter);
2654- g_object_unref(session);
2655-}
2656-
2657-

Subscribers

People subscribed via source and target branches