Merge lp:~ted/ubuntu-app-launch/gir-support into lp:ubuntu-app-launch/14.04

Proposed by Ted Gould
Status: Merged
Approved by: Ted Gould
Approved revision: 118
Merged at revision: 126
Proposed branch: lp:~ted/ubuntu-app-launch/gir-support
Merge into: lp:ubuntu-app-launch/14.04
Diff against target: 3978 lines (+2028/-908)
38 files modified
CMakeLists.txt (+31/-24)
application-failed.c (+72/-0)
application-failed.conf.in (+6/-0)
application-job.c (+113/-0)
application.conf.in (+1/-21)
cmake/FindGObjectIntrospection.cmake (+61/-0)
cmake/ListOperations.cmake (+18/-0)
cmake/UseGObjectIntrospection.cmake (+102/-0)
data/com.canonical.UpstartAppLaunch.xml (+4/-0)
debian/changelog (+6/-0)
debian/control (+17/-0)
debian/gir1.2-upstart-app-launch-2.install (+1/-0)
debian/libupstart-app-launch2-dev.install (+1/-0)
debian/rules (+1/-1)
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 (+32/-0)
libupstart-app-launch/second-exec-core.c (+145/-103)
libupstart-app-launch/upstart-app-launch-trace.tp (+170/-0)
libupstart-app-launch/upstart-app-launch.c (+533/-242)
libupstart-app-launch/upstart-app-launch.h (+54/-48)
second-exec-trace.tp (+0/-16)
second-exec.c (+0/-40)
tests/CMakeLists.txt (+10/-18)
tests/applications/multiple.desktop (+8/-0)
tests/applications/single.desktop (+8/-0)
tests/failure-test.cc (+151/-0)
tests/libual-test.cc (+318/-40)
tests/link-farm/README (+3/-0)
tests/link-farm/foo.desktop (+1/-0)
tests/link-farm/foolike.desktop (+1/-0)
tests/manual (+7/-0)
tests/second-exec-test.cc (+0/-205)
tests/zg-test.cc (+55/-0)
upstart-app-watch.c (+1/-1)
zg-report-app.c (+2/-2)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/gir-support
Reviewer Review Type Date Requested Status
Thomi Richards (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+201681@code.launchpad.net

Commit message

Add GIR support to libual

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
116. By Ted Gould

Better annotate the URI list

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
117. By Ted Gould

Adding dh rules for GIR

118. By Ted Gould

Install in the right path

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

Hi,

My observers aren't being called. This is the test script I'm using:
http://paste.ubuntu.com/6794482/

The observer for 'failed' fails to be added (but that's expected apparently), but none of the observers are ever called. gedit opens as expected, so at least the application launching works.

review: Needs Fixing
Revision history for this message
Ted Gould (ted) wrote :

On Tue, 2014-01-21 at 23:44 +0000, Thomi Richards wrote:

> My observers aren't being called. This is the test script I'm using:
> http:��paste.ubuntu.com�6794482�

Switching to have a mainloop and changing the prototype of the callback
seems to fix it for me:

http:��paste.ubuntu.com�6795288�

Revision history for this message
Thomi Richards (thomir-deactivatedaccount) wrote :

LGTM

review: Approve
119. By Ted Gould

Updating to future trunk

120. By Ted Gould

Only parse the header for introspection information

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-11 03:28:22 +0000
4@@ -9,6 +9,7 @@
5 set(PACKAGE ${CMAKE_PROJECT_NAME})
6
7 find_package(PkgConfig REQUIRED)
8+find_package(GObjectIntrospection REQUIRED)
9 include(GNUInstallDirs)
10 include(CheckIncludeFile)
11 include(CheckFunctionExists)
12@@ -51,9 +52,12 @@
13 pkg_check_modules(ZEITGEIST REQUIRED zeitgeist-2.0)
14 include_directories(${ZEITGEIST_INCLUDE_DIRS})
15
16-pkg_check_modules(LIBUPSTART REQUIRED libupstart libnih libnih-dbus dbus-1)
17+pkg_check_modules(LIBUPSTART REQUIRED libupstart)
18 include_directories(${LIBUPSTART_INCLUDE_DIRS})
19
20+pkg_check_modules(DBUS REQUIRED dbus-1)
21+include_directories(${DBUS_INCLUDE_DIRS})
22+
23 pkg_check_modules(DBUSTEST REQUIRED dbustest-1>=14.04.0)
24 include_directories(${DBUSTEST_INCLUDE_DIRS})
25
26@@ -68,7 +72,7 @@
27 # Helpers
28 ####################
29
30-add_library(helpers STATIC helpers.c)
31+add_library(helpers STATIC helpers.c helpers-keyfile.c)
32 target_link_libraries(helpers ${GIO2_LIBRARIES} ${JSONGLIB_LIBRARIES})
33
34 ####################
35@@ -146,16 +150,6 @@
36 install(TARGETS desktop-hook RUNTIME DESTINATION "${pkglibexecdir}")
37
38 ####################
39-# desktop-single
40-####################
41-
42-add_lttng_gen_tp(NAME desktop-single-trace)
43-add_executable(desktop-single desktop-single.c desktop-single-trace.c)
44-set_target_properties(desktop-single PROPERTIES OUTPUT_NAME "desktop-single")
45-target_link_libraries(desktop-single helpers ${LTTNG_LIBRARIES})
46-install(TARGETS desktop-single RUNTIME DESTINATION "${pkglibexecdir}")
47-
48-####################
49 # exec-line-exec
50 ####################
51
52@@ -175,18 +169,23 @@
53 target_link_libraries(zg-report-app ${ZEITGEIST_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GLIB2_LIBRARIES})
54 install(TARGETS zg-report-app RUNTIME DESTINATION "${pkglibexecdir}")
55
56-#######################
57-# second-exec
58-#######################
59-
60-add_lttng_gen_tp(NAME second-exec-trace)
61-add_library(second-exec-core STATIC second-exec-core.c second-exec-trace.c)
62-target_link_libraries(second-exec-core helpers upstart-launcher ${LTTNG_LIBRARIES})
63-
64-add_executable(second-exec second-exec.c)
65-set_target_properties(second-exec PROPERTIES OUTPUT_NAME "second-exec")
66-target_link_libraries(second-exec second-exec-core)
67-install(TARGETS second-exec RUNTIME DESTINATION "${pkglibexecdir}")
68+####################
69+# application-job
70+####################
71+
72+add_executable(application-job application-job.c)
73+set_target_properties(application-job PROPERTIES OUTPUT_NAME "application-job")
74+target_link_libraries(application-job upstart-launcher)
75+install(TARGETS application-job RUNTIME DESTINATION "${pkglibexecdir}")
76+
77+####################
78+# application-failed
79+####################
80+
81+add_executable(application-failed application-failed.c)
82+set_target_properties(application-failed PROPERTIES OUTPUT_NAME "application-failed")
83+target_link_libraries(application-failed ${GIO2_LIBRARIES})
84+install(TARGETS application-failed RUNTIME DESTINATION "${pkglibexecdir}")
85
86 ####################
87 # application.conf
88@@ -213,6 +212,14 @@
89 add_test(application-click.conf.test "${CMAKE_SOURCE_DIR}/test-conffile.sh" "${CMAKE_CURRENT_BINARY_DIR}/application-click.conf")
90
91 ####################
92+# application-failed.conf
93+####################
94+
95+configure_file("application-failed.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/application-failed.conf" @ONLY)
96+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/application-failed.conf" DESTINATION "${CMAKE_INSTALL_DATADIR}/upstart/sessions")
97+add_test(application-failed.conf.test "${CMAKE_SOURCE_DIR}/test-conffile.sh" "${CMAKE_CURRENT_BINARY_DIR}/application-failed.conf")
98+
99+####################
100 # upstart-app-launch-desktop.click-hook
101 ####################
102
103
104=== added file 'application-failed.c'
105--- application-failed.c 1970-01-01 00:00:00 +0000
106+++ application-failed.c 2014-02-11 03:28:22 +0000
107@@ -0,0 +1,72 @@
108+
109+/*
110+ * Copyright 2013 Canonical Ltd.
111+ *
112+ * This program is free software: you can redistribute it and/or modify it
113+ * under the terms of the GNU General Public License version 3, as published
114+ * by the Free Software Foundation.
115+ *
116+ * This program is distributed in the hope that it will be useful, but
117+ * WITHOUT ANY WARRANTY; without even the implied warranties of
118+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
119+ * PURPOSE. See the GNU General Public License for more details.
120+ *
121+ * You should have received a copy of the GNU General Public License along
122+ * with this program. If not, see <http://www.gnu.org/licenses/>.
123+ *
124+ * Authors:
125+ * Ted Gould <ted.gould@canonical.com>
126+ */
127+
128+#include <gio/gio.h>
129+
130+int
131+main (int argc, char * argv[])
132+{
133+ const gchar * job = g_getenv("JOB");
134+ g_return_val_if_fail(job != NULL, -1);
135+
136+ const gchar * instance = g_getenv("INSTANCE");
137+ g_return_val_if_fail(instance != NULL, -1);
138+
139+ gboolean crashed = FALSE;
140+ if (g_getenv("EXIT_STATUS") != NULL || g_getenv("EXIT_SIGNAL") != NULL) {
141+ crashed = TRUE;
142+ }
143+
144+ gchar * appid = g_strdup(instance);
145+ if (g_strcmp0(job, "application-legacy") == 0) {
146+ gchar * lasthyphenstanding = g_strrstr(appid, "-");
147+ if (lasthyphenstanding != NULL) {
148+ lasthyphenstanding[0] = '\0';
149+ } else {
150+ g_warning("Legacy job instance '%s' is missing a hyphen", appid);
151+ }
152+ }
153+
154+ GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
155+ g_return_val_if_fail(bus != NULL, -1);
156+
157+ GError * error = NULL;
158+ g_dbus_connection_emit_signal(bus,
159+ NULL, /* destination */
160+ "/", /* path */
161+ "com.canonical.UpstartAppLaunch",
162+ "ApplicationFailed",
163+ g_variant_new("(ss)", appid, crashed ? "crash" : "start-failure"),
164+ &error);
165+
166+ g_debug("Emitting failed event '%s' for app '%s'", crashed ? "crash" : "start-failure", appid);
167+
168+ if (error != NULL) {
169+ g_warning("Unable to emit signal: %s", error->message);
170+ g_error_free(error);
171+ return -1;
172+ }
173+
174+ g_dbus_connection_flush_sync(bus, NULL, NULL);
175+ g_object_unref(bus);
176+ g_free(appid);
177+
178+ return 0;
179+}
180
181=== added file 'application-failed.conf.in'
182--- application-failed.conf.in 1970-01-01 00:00:00 +0000
183+++ application-failed.conf.in 2014-02-11 03:28:22 +0000
184@@ -0,0 +1,6 @@
185+description "Application Failing"
186+
187+start on stopped application-legacy RESULT=failed or stopped application-click RESULT=failed
188+task
189+
190+exec @pkglibexecdir@/application-failed
191
192=== added file 'application-job.c'
193--- application-job.c 1970-01-01 00:00:00 +0000
194+++ application-job.c 2014-02-11 03:28:22 +0000
195@@ -0,0 +1,113 @@
196+/*
197+ * Copyright 2013 Canonical Ltd.
198+ *
199+ * This program is free software: you can redistribute it and/or modify it
200+ * under the terms of the GNU General Public License version 3, as published
201+ * by the Free Software Foundation.
202+ *
203+ * This program is distributed in the hope that it will be useful, but
204+ * WITHOUT ANY WARRANTY; without even the implied warranties of
205+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
206+ * PURPOSE. See the GNU General Public License for more details.
207+ *
208+ * You should have received a copy of the GNU General Public License along
209+ * with this program. If not, see <http://www.gnu.org/licenses/>.
210+ *
211+ * Authors:
212+ * Ted Gould <ted.gould@canonical.com>
213+ */
214+
215+#include <gio/gio.h>
216+#include "libupstart-app-launch/upstart-app-launch.h"
217+
218+int retval = 0;
219+const gchar * global_appid;
220+
221+static void
222+app_started (const gchar * appid, gpointer user_data)
223+{
224+ if (g_strcmp0(appid, global_appid) != 0)
225+ return;
226+ g_debug("Application Started: %s", appid);
227+ g_main_loop_quit((GMainLoop *)user_data);
228+}
229+
230+static void
231+app_focus (const gchar * appid, gpointer user_data)
232+{
233+ if (g_strcmp0(appid, global_appid) != 0)
234+ return;
235+ g_debug("Application Focused");
236+ g_main_loop_quit((GMainLoop *)user_data);
237+}
238+
239+static void
240+app_failed (const gchar * appid, upstart_app_launch_app_failed_t failure_type, gpointer user_data)
241+{
242+ if (g_strcmp0(appid, global_appid) != 0)
243+ return;
244+ g_warning("Application Startup Failed");
245+ retval = 1;
246+ g_main_loop_quit((GMainLoop *)user_data);
247+}
248+
249+/* A fallback so that we can see what is going on. The job can not always signal
250+ that it has been started, and thus we wouldn't quit. Which would be a bad thing. */
251+static gboolean
252+timeout_check (gpointer user_data)
253+{
254+ g_debug("Timeout reached");
255+ g_main_loop_quit((GMainLoop *)user_data);
256+ return TRUE; /* Keep the source connected to avoid the disconnect error */
257+}
258+
259+int
260+main (int argc, char * argv[])
261+{
262+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
263+ g_return_val_if_fail(con != NULL, 1);
264+
265+ global_appid = g_getenv("APP_ID");
266+ g_return_val_if_fail(global_appid != NULL, 1);
267+
268+ const gchar * uris_str = g_getenv("APP_URIS");
269+ gchar ** uris = NULL;
270+ if (uris_str != NULL) {
271+ GError * error = NULL;
272+ gint uri_count = 0;
273+ g_shell_parse_argv(uris_str, &uri_count, &uris, &error);
274+
275+ if (error != NULL) {
276+ g_warning("Unable to parse uris '%s': %s", uris_str, error->message);
277+ g_error_free(error);
278+ } else {
279+ g_debug("Got %d URIs", uri_count);
280+ }
281+ }
282+
283+ GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
284+
285+ upstart_app_launch_observer_add_app_started(app_started, mainloop);
286+ upstart_app_launch_observer_add_app_focus(app_focus, mainloop);
287+ upstart_app_launch_observer_add_app_failed(app_failed, mainloop);
288+
289+ guint timer = g_timeout_add_seconds(1, timeout_check, mainloop);
290+
291+ g_debug("Start Application: %s", global_appid);
292+ g_return_val_if_fail(upstart_app_launch_start_application(global_appid, (const gchar * const *)uris), -1);
293+ g_strfreev(uris);
294+
295+ g_debug("Wait for results");
296+ g_main_loop_run(mainloop);
297+
298+ g_source_remove(timer);
299+
300+ upstart_app_launch_observer_delete_app_started(app_started, mainloop);
301+ upstart_app_launch_observer_delete_app_focus(app_focus, mainloop);
302+ upstart_app_launch_observer_delete_app_failed(app_failed, mainloop);
303+
304+ g_main_loop_unref(mainloop);
305+ g_object_unref(con);
306+
307+ return retval;
308+}
309
310=== modified file 'application.conf.in'
311--- application.conf.in 2014-01-22 22:48:58 +0000
312+++ application.conf.in 2014-02-11 03:28:22 +0000
313@@ -14,24 +14,4 @@
314 env APP_URIS
315 export APP_URIS
316
317-script
318- CLICK_PKG=`echo "${APP_ID}" | cut -d _ -f 1`
319-
320- if [ ! -z $CLICK_PKG ] ; then
321- CLICK_DIR=`click pkgdir "${CLICK_PKG}" 2> /dev/null || true`
322- fi
323-
324- if [ ! -z $CLICK_DIR ] && [ -d $CLICK_DIR ] ; then
325- if ! start application-click APP_ID="${APP_ID}" APP_URIS="${APP_URIS}"; then
326- @pkglibexecdir@/second-exec
327- fi
328- else
329- if @pkglibexecdir@/desktop-single $APP_ID ; then
330- if ! start application-legacy APP_ID="${APP_ID}" INSTANCE_ID="" APP_URIS="${APP_URIS}" ; then
331- @pkglibexecdir@/second-exec
332- fi
333- else
334- start application-legacy APP_ID="${APP_ID}" INSTANCE_ID=`date -u +%s` APP_URIS="${APP_URIS}"
335- fi
336- fi
337-end script
338+exec @pkglibexecdir@/application-job
339
340=== added file 'cmake/FindGObjectIntrospection.cmake'
341--- cmake/FindGObjectIntrospection.cmake 1970-01-01 00:00:00 +0000
342+++ cmake/FindGObjectIntrospection.cmake 2014-02-11 03:28:22 +0000
343@@ -0,0 +1,61 @@
344+# - try to find gobject-introspection
345+#
346+# Once done this will define
347+#
348+# INTROSPECTION_FOUND - system has gobject-introspection
349+# INTROSPECTION_SCANNER - the gobject-introspection scanner, g-ir-scanner
350+# INTROSPECTION_COMPILER - the gobject-introspection compiler, g-ir-compiler
351+# INTROSPECTION_GENERATE - the gobject-introspection generate, g-ir-generate
352+# INTROSPECTION_GIRDIR
353+# INTROSPECTION_TYPELIBDIR
354+# INTROSPECTION_CFLAGS
355+# INTROSPECTION_LIBS
356+#
357+# Copyright (C) 2010, Pino Toscano, <pino@kde.org>
358+#
359+# Redistribution and use is allowed according to the terms of the BSD license.
360+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
361+
362+macro(_GIR_GET_PKGCONFIG_VAR _outvar _varname)
363+ execute_process(
364+ COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=${_varname} gobject-introspection-1.0
365+ OUTPUT_VARIABLE _result
366+ RESULT_VARIABLE _null
367+ )
368+
369+ if (_null)
370+ else()
371+ string(REGEX REPLACE "[\r\n]" " " _result "${_result}")
372+ string(REGEX REPLACE " +$" "" _result "${_result}")
373+ separate_arguments(_result)
374+ set(${_outvar} ${_result} CACHE INTERNAL "")
375+ endif()
376+endmacro(_GIR_GET_PKGCONFIG_VAR)
377+
378+find_package(PkgConfig)
379+if(PKG_CONFIG_FOUND)
380+ if(PACKAGE_FIND_VERSION_COUNT GREATER 0)
381+ set(_gir_version_cmp ">=${PACKAGE_FIND_VERSION}")
382+ endif()
383+ pkg_check_modules(_pc_gir gobject-introspection-1.0${_gir_version_cmp})
384+ if(_pc_gir_FOUND)
385+ set(INTROSPECTION_FOUND TRUE)
386+ _gir_get_pkgconfig_var(INTROSPECTION_SCANNER "g_ir_scanner")
387+ _gir_get_pkgconfig_var(INTROSPECTION_COMPILER "g_ir_compiler")
388+ _gir_get_pkgconfig_var(INTROSPECTION_GENERATE "g_ir_generate")
389+ _gir_get_pkgconfig_var(INTROSPECTION_GIRDIR "girdir")
390+ _gir_get_pkgconfig_var(INTROSPECTION_TYPELIBDIR "typelibdir")
391+ set(INTROSPECTION_CFLAGS "${_pc_gir_CFLAGS}")
392+ set(INTROSPECTION_LIBS "${_pc_gir_LIBS}")
393+ endif()
394+endif()
395+
396+mark_as_advanced(
397+ INTROSPECTION_SCANNER
398+ INTROSPECTION_COMPILER
399+ INTROSPECTION_GENERATE
400+ INTROSPECTION_GIRDIR
401+ INTROSPECTION_TYPELIBDIR
402+ INTROSPECTION_CFLAGS
403+ INTROSPECTION_LIBS
404+)
405
406=== added file 'cmake/ListOperations.cmake'
407--- cmake/ListOperations.cmake 1970-01-01 00:00:00 +0000
408+++ cmake/ListOperations.cmake 2014-02-11 03:28:22 +0000
409@@ -0,0 +1,18 @@
410+
411+macro(list_prefix _outvar _listvar _prefix)
412+ set(${_outvar})
413+ foreach(_item IN LISTS ${_listvar})
414+ list(APPEND ${_outvar} ${_prefix}${_item})
415+ endforeach()
416+endmacro(list_prefix)
417+
418+macro(list_make_absolute _outvar _listvar _prefix)
419+ set(${_outvar})
420+ foreach(_item IN LISTS ${_listvar})
421+ if(IS_ABSOLUTE ${_item})
422+ list(APPEND ${_outvar} ${_item})
423+ else()
424+ list(APPEND ${_outvar} ${_prefix}${_item})
425+ endif()
426+ endforeach()
427+endmacro(list_make_absolute)
428
429=== added file 'cmake/UseGObjectIntrospection.cmake'
430--- cmake/UseGObjectIntrospection.cmake 1970-01-01 00:00:00 +0000
431+++ cmake/UseGObjectIntrospection.cmake 2014-02-11 03:28:22 +0000
432@@ -0,0 +1,102 @@
433+# Copyright (C) 2010, Pino Toscano, <pino@kde.org>
434+#
435+# Redistribution and use is allowed according to the terms of the BSD license.
436+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
437+
438+include(ListOperations)
439+
440+macro(_gir_list_prefix _outvar _listvar _prefix)
441+ set(${_outvar})
442+ foreach(_item IN LISTS ${_listvar})
443+ list(APPEND ${_outvar} ${_prefix}${_item})
444+ endforeach()
445+endmacro(_gir_list_prefix)
446+
447+macro(gir_add_introspections introspections_girs)
448+
449+ foreach(gir IN LISTS ${introspections_girs})
450+
451+ set(_gir_name "${gir}")
452+
453+ ## Transform the gir filename to something which can reference through a variable
454+ ## without automake/make complaining, eg Gtk-2.0.gir -> Gtk_2_0_gir
455+ string(REPLACE "-" "_" _gir_name "${_gir_name}")
456+ string(REPLACE "." "_" _gir_name "${_gir_name}")
457+
458+ # Namespace and Version is either fetched from the gir filename
459+ # or the _NAMESPACE/_VERSION variable combo
460+ set(_gir_namespace "${${_gir_name}_NAMESPACE}")
461+ if (_gir_namespace STREQUAL "")
462+ string(REGEX REPLACE "([^-]+)-.*" "\\1" _gir_namespace "${gir}")
463+ endif ()
464+ set(_gir_version "${${_gir_name}_VERSION}")
465+ if (_gir_version STREQUAL "")
466+ string(REGEX REPLACE ".*-([^-]+).gir" "\\1" _gir_version "${gir}")
467+ endif ()
468+
469+ # _PROGRAM is an optional variable which needs it's own --program argument
470+ set(_gir_program "${${_gir_name}_PROGRAM}")
471+ if (NOT _gir_program STREQUAL "")
472+ set(_gir_program "--program=${_gir_program}")
473+ endif ()
474+
475+ # Variables which provides a list of things
476+ _gir_list_prefix(_gir_libraries ${_gir_name}_LIBS "--library=")
477+ _gir_list_prefix(_gir_packages ${_gir_name}_PACKAGES "--pkg=")
478+ _gir_list_prefix(_gir_includes ${_gir_name}_INCLUDES "--include=")
479+ _gir_list_prefix(_gir_export_packages ${_gir_name}_EXPORT_PACKAGES "--pkg-export=")
480+
481+ # Reuse the LIBTOOL variable from by automake if it's set
482+ set(_gir_libtool "--no-libtool")
483+
484+ add_custom_command(
485+ COMMAND ${INTROSPECTION_SCANNER}
486+ ${INTROSPECTION_SCANNER_ARGS}
487+ --quiet
488+ --warn-all
489+ --namespace=${_gir_namespace}
490+ --nsversion=${_gir_version}
491+ ${_gir_libtool}
492+ ${_gir_program}
493+ ${_gir_libraries}
494+ ${_gir_packages}
495+ ${_gir_includes}
496+ ${_gir_export_packages}
497+ ${${_gir_name}_SCANNERFLAGS}
498+ ${${_gir_name}_CFLAGS}
499+ ${${_gir_name}_FILES}
500+ --output ${CMAKE_CURRENT_BINARY_DIR}/${gir}
501+ DEPENDS ${${_gir_name}_FILES}
502+ ${${_gir_name}_LIBS}
503+ OUTPUT ${gir}
504+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
505+ VERBATIM
506+ )
507+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${gir} DESTINATION share/gir-1.0)
508+
509+ string(REPLACE ".gir" ".typelib" _typelib "${gir}")
510+ add_custom_command(
511+ COMMAND ${INTROSPECTION_COMPILER}
512+ ${INTROSPECTION_COMPILER_ARGS}
513+ --includedir=.
514+ ${CMAKE_CURRENT_BINARY_DIR}/${gir}
515+ -o ${CMAKE_CURRENT_BINARY_DIR}/${_typelib}
516+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${gir}
517+ OUTPUT ${_typelib}
518+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
519+ )
520+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_typelib} DESTINATION ${CMAKE_INSTALL_LIBDIR}/girepository-1.0)
521+
522+ add_custom_target(gir-${gir} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${gir})
523+ add_custom_target(gir-typelibs-${_typelib} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${_typelib})
524+ endforeach()
525+
526+endmacro(gir_add_introspections)
527+
528+macro(gir_get_cflags _output)
529+ get_directory_property(_tmp_includes INCLUDE_DIRECTORIES)
530+ list_prefix(_includes _tmp_includes "-I")
531+ get_directory_property(_tmp_compile_definitions COMPILE_DEFINITIONS)
532+ list_prefix(_compile_definitions _tmp_compile_definitions "-D")
533+ set(${_output} ${_includes} ${_compile_definitions})
534+endmacro(gir_get_cflags)
535
536=== modified file 'data/com.canonical.UpstartAppLaunch.xml'
537--- data/com.canonical.UpstartAppLaunch.xml 2013-12-06 10:48:02 +0000
538+++ data/com.canonical.UpstartAppLaunch.xml 2014-02-11 03:28:22 +0000
539@@ -16,5 +16,9 @@
540 <signal name="UnityStartingSignal">
541 <arg type="s" name="appid" />
542 </signal>
543+ <signal name="ApplicationFailed">
544+ <arg type="s" name="appid" />
545+ <arg type="s" name="stage" />
546+ </signal>
547 </interface>
548 </node>
549
550=== modified file 'debian/changelog'
551--- debian/changelog 2014-02-06 16:54:55 +0000
552+++ debian/changelog 2014-02-11 03:28:22 +0000
553@@ -1,3 +1,9 @@
554+upstart-app-launch (0.3+14.04.20140210-0ubuntu1) trusty; urgency=low
555+
556+ *
557+
558+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 10 Feb 2014 10:25:19 +0000
559+
560 upstart-app-launch (0.3+14.04.20140206-0ubuntu1) trusty; urgency=low
561
562 [ Ted Gould ]
563
564=== modified file 'debian/control'
565--- debian/control 2014-01-13 15:16:24 +0000
566+++ debian/control 2014-02-11 03:28:22 +0000
567@@ -9,6 +9,7 @@
568 debhelper (>= 9),
569 libdbus-1-dev,
570 libdbustest1-dev (>= 14.04.0),
571+ libgirepository1.0-dev,
572 libglib2.0-dev,
573 libgtest-dev,
574 libjson-glib-dev,
575@@ -17,6 +18,7 @@
576 libnih-dev,
577 libupstart-dev,
578 libzeitgeist-2.0-dev,
579+ gobject-introspection,
580 python3-dbusmock,
581 upstart (>= 1.11),
582 Standards-Version: 3.9.4
583@@ -80,3 +82,18 @@
584 .
585 This package contains files that are needed to build applications.
586
587+Package: gir1.2-upstart-app-launch-2
588+Section: libs
589+Architecture: any
590+Depends: ${shlibs:Depends},
591+ ${misc:Depends},
592+ libupstart-app-launch2 (= ${binary:Version}),
593+ ${gir:Depends},
594+Pre-Depends: ${misc:Pre-Depends}
595+Recommends: upstart-app-launch (= ${binary:Version})
596+Description: typelib file for libupstart-app-launch2
597+ Interface for starting apps and getting info on them.
598+ .
599+ This package can be used by other packages using the GIRepository format to
600+ generate dynamic bindings for libupstart-app-launch2.
601+
602
603=== added file 'debian/gir1.2-upstart-app-launch-2.install'
604--- debian/gir1.2-upstart-app-launch-2.install 1970-01-01 00:00:00 +0000
605+++ debian/gir1.2-upstart-app-launch-2.install 2014-02-11 03:28:22 +0000
606@@ -0,0 +1,1 @@
607+usr/lib/*/girepository-1.0 /usr/lib
608
609=== modified file 'debian/libupstart-app-launch2-dev.install'
610--- debian/libupstart-app-launch2-dev.install 2013-12-05 17:19:45 +0000
611+++ debian/libupstart-app-launch2-dev.install 2014-02-11 03:28:22 +0000
612@@ -1,3 +1,4 @@
613 usr/lib/*/libupstart-app-launch.so
614 usr/lib/*/pkgconfig/*
615 usr/include/*
616+usr/share/gir-1.0/*
617
618=== modified file 'debian/rules'
619--- debian/rules 2013-07-24 16:57:23 +0000
620+++ debian/rules 2014-02-11 03:28:22 +0000
621@@ -5,7 +5,7 @@
622 #export DH_VERBOSE=1
623
624 %:
625- dh $@ --with click
626+ dh $@ --with click,gir
627
628 override_dh_click:
629 dh_click --name upstart-app-launch-desktop
630
631=== removed file 'desktop-single-trace.tp'
632--- desktop-single-trace.tp 2013-12-04 17:10:57 +0000
633+++ desktop-single-trace.tp 1970-01-01 00:00:00 +0000
634@@ -1,5 +0,0 @@
635-
636-TRACEPOINT_EVENT(upstart_app_launch, desktop_single_start, TP_ARGS(0), TP_FIELDS())
637-TRACEPOINT_EVENT(upstart_app_launch, desktop_single_found, TP_ARGS(0), TP_FIELDS())
638-TRACEPOINT_EVENT(upstart_app_launch, desktop_single_finished, TP_ARGS(0), TP_FIELDS())
639-
640
641=== removed file 'desktop-single.c'
642--- desktop-single.c 2013-12-05 17:08:13 +0000
643+++ desktop-single.c 1970-01-01 00:00:00 +0000
644@@ -1,68 +0,0 @@
645-/*
646- * Copyright 2013 Canonical Ltd.
647- *
648- * This program is free software: you can redistribute it and/or modify it
649- * under the terms of the GNU General Public License version 3, as published
650- * by the Free Software Foundation.
651- *
652- * This program is distributed in the hope that it will be useful, but
653- * WITHOUT ANY WARRANTY; without even the implied warranties of
654- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
655- * PURPOSE. See the GNU General Public License for more details.
656- *
657- * You should have received a copy of the GNU General Public License along
658- * with this program. If not, see <http://www.gnu.org/licenses/>.
659- *
660- * Authors:
661- * Ted Gould <ted.gould@canonical.com>
662- */
663-
664-#include "helpers.h"
665-#include "desktop-single-trace.h"
666-
667-int
668-main (int argc, char * argv[])
669-{
670- /* Nothing is single instance yet */
671- if (argc != 2) {
672- g_error("Should be called as: %s <app_id>", argv[0]);
673- return 1;
674- }
675-
676- g_setenv("LTTNG_UST_REGISTER_TIMEOUT", "0", FALSE); /* Set to zero if not set */
677- tracepoint(upstart_app_launch, desktop_single_start);
678-
679- GKeyFile * keyfile = keyfile_for_appid(argv[1], NULL);
680-
681- if (keyfile == NULL) {
682- g_error("Unable to find keyfile for application '%s'", argv[0]);
683- return 1;
684- }
685-
686- tracepoint(upstart_app_launch, desktop_single_found);
687-
688- gboolean singleinstance = FALSE;
689-
690- if (g_key_file_has_key(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", NULL)) {
691- GError * error = NULL;
692-
693- singleinstance = g_key_file_get_boolean(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", &error);
694-
695- if (error != NULL) {
696- g_warning("Unable to get single instance key for app '%s': %s", argv[1], error->message);
697- g_error_free(error);
698- /* Ensure that if we got an error, we assume standard case */
699- singleinstance = FALSE;
700- }
701- }
702-
703- g_key_file_free(keyfile);
704-
705- tracepoint(upstart_app_launch, desktop_single_finished);
706-
707- if (singleinstance) {
708- return 0;
709- } else {
710- return 1;
711- }
712-}
713
714=== added file 'helpers-keyfile.c'
715--- helpers-keyfile.c 1970-01-01 00:00:00 +0000
716+++ helpers-keyfile.c 2014-02-11 03:28:22 +0000
717@@ -0,0 +1,95 @@
718+/*
719+ * Copyright 2013 Canonical Ltd.
720+ *
721+ * This program is free software: you can redistribute it and/or modify it
722+ * under the terms of the GNU General Public License version 3, as published
723+ * by the Free Software Foundation.
724+ *
725+ * This program is distributed in the hope that it will be useful, but
726+ * WITHOUT ANY WARRANTY; without even the implied warranties of
727+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
728+ * PURPOSE. See the GNU General Public License for more details.
729+ *
730+ * You should have received a copy of the GNU General Public License along
731+ * with this program. If not, see <http://www.gnu.org/licenses/>.
732+ *
733+ * Authors:
734+ * Ted Gould <ted.gould@canonical.com>
735+ */
736+
737+#include "helpers.h"
738+
739+/* Check to make sure we have the sections and keys we want */
740+static gboolean
741+verify_keyfile (GKeyFile * inkeyfile, const gchar * desktop)
742+{
743+ if (inkeyfile == NULL) return FALSE;
744+
745+ if (!g_key_file_has_group(inkeyfile, "Desktop Entry")) {
746+ g_warning("Desktop file '%s' is missing the 'Desktop Entry' group", desktop);
747+ return FALSE;
748+ }
749+
750+ if (!g_key_file_has_key(inkeyfile, "Desktop Entry", "Exec", NULL)) {
751+ g_warning("Desktop file '%s' is missing the 'Exec' key", desktop);
752+ return FALSE;
753+ }
754+
755+ return TRUE;
756+}
757+
758+/* Try to find a desktop file in a particular data directory */
759+static GKeyFile *
760+try_dir (const char * dir, const gchar * desktop)
761+{
762+ gchar * fullpath = g_build_filename(dir, "applications", desktop, NULL);
763+ GKeyFile * keyfile = g_key_file_new();
764+
765+ /* NOTE: Leaving off the error here as we'll get a bunch of them,
766+ so individuals aren't really useful */
767+ gboolean loaded = g_key_file_load_from_file(keyfile, fullpath, G_KEY_FILE_NONE, NULL);
768+
769+ g_free(fullpath);
770+
771+ if (!loaded) {
772+ g_key_file_free(keyfile);
773+ return NULL;
774+ }
775+
776+ if (!verify_keyfile(keyfile, desktop)) {
777+ g_key_file_free(keyfile);
778+ return NULL;
779+ }
780+
781+ return keyfile;
782+}
783+
784+/* Find the keyfile that we need for a particular AppID and return it.
785+ Or NULL if we can't find it. */
786+GKeyFile *
787+keyfile_for_appid (const gchar * appid, gchar ** desktopfile)
788+{
789+ gchar * desktop = g_strdup_printf("%s.desktop", appid);
790+
791+ const char * const * data_dirs = g_get_system_data_dirs();
792+ GKeyFile * keyfile = NULL;
793+ int i;
794+
795+ keyfile = try_dir(g_get_user_data_dir(), desktop);
796+ if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
797+ *desktopfile = g_build_filename(g_get_user_data_dir(), "applications", desktop, NULL);
798+ }
799+
800+ for (i = 0; data_dirs[i] != NULL && keyfile == NULL; i++) {
801+ keyfile = try_dir(data_dirs[i], desktop);
802+
803+ if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
804+ *desktopfile = g_build_filename(data_dirs[i], "applications", desktop, NULL);
805+ }
806+ }
807+
808+ g_free(desktop);
809+
810+ return keyfile;
811+}
812+
813
814=== modified file 'helpers.c'
815--- helpers.c 2014-02-03 18:29:54 +0000
816+++ helpers.c 2014-02-11 03:28:22 +0000
817@@ -492,80 +492,6 @@
818 return newargv;
819 }
820
821-/* Check to make sure we have the sections and keys we want */
822-static gboolean
823-verify_keyfile (GKeyFile * inkeyfile, const gchar * desktop)
824-{
825- if (inkeyfile == NULL) return FALSE;
826-
827- if (!g_key_file_has_group(inkeyfile, "Desktop Entry")) {
828- g_warning("Desktop file '%s' is missing the 'Desktop Entry' group", desktop);
829- return FALSE;
830- }
831-
832- if (!g_key_file_has_key(inkeyfile, "Desktop Entry", "Exec", NULL)) {
833- g_warning("Desktop file '%s' is missing the 'Exec' key", desktop);
834- return FALSE;
835- }
836-
837- return TRUE;
838-}
839-
840-/* Try to find a desktop file in a particular data directory */
841-static GKeyFile *
842-try_dir (const char * dir, const gchar * desktop)
843-{
844- gchar * fullpath = g_build_filename(dir, "applications", desktop, NULL);
845- GKeyFile * keyfile = g_key_file_new();
846-
847- /* NOTE: Leaving off the error here as we'll get a bunch of them,
848- so individuals aren't really useful */
849- gboolean loaded = g_key_file_load_from_file(keyfile, fullpath, G_KEY_FILE_NONE, NULL);
850-
851- g_free(fullpath);
852-
853- if (!loaded) {
854- g_key_file_free(keyfile);
855- return NULL;
856- }
857-
858- if (!verify_keyfile(keyfile, desktop)) {
859- g_key_file_free(keyfile);
860- return NULL;
861- }
862-
863- return keyfile;
864-}
865-
866-/* Find the keyfile that we need for a particular AppID and return it.
867- Or NULL if we can't find it. */
868-GKeyFile *
869-keyfile_for_appid (const gchar * appid, gchar ** desktopfile)
870-{
871- gchar * desktop = g_strdup_printf("%s.desktop", appid);
872-
873- const char * const * data_dirs = g_get_system_data_dirs();
874- GKeyFile * keyfile = NULL;
875- int i;
876-
877- keyfile = try_dir(g_get_user_data_dir(), desktop);
878- if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
879- *desktopfile = g_build_filename(g_get_user_data_dir(), "applications", desktop, NULL);
880- }
881-
882- for (i = 0; data_dirs[i] != NULL && keyfile == NULL; i++) {
883- keyfile = try_dir(data_dirs[i], desktop);
884-
885- if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
886- *desktopfile = g_build_filename(data_dirs[i], "applications", desktop, NULL);
887- }
888- }
889-
890- g_free(desktop);
891-
892- return keyfile;
893-}
894-
895 /* Set environment various variables to make apps work under
896 * confinement according to:
897 * https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement
898
899=== modified file 'libupstart-app-launch/CMakeLists.txt'
900--- libupstart-app-launch/CMakeLists.txt 2014-01-13 15:16:24 +0000
901+++ libupstart-app-launch/CMakeLists.txt 2014-02-11 03:28:22 +0000
902@@ -1,4 +1,7 @@
903
904+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
905+include_directories(${CMAKE_CURRENT_BINARY_DIR})
906+
907 ##########################
908 # Version Info
909 ##########################
910@@ -11,6 +14,8 @@
911 # Library
912 ##########################
913
914+add_lttng_gen_tp(NAME upstart-app-launch-trace)
915+
916 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
917
918 set(LAUNCHER_HEADERS
919@@ -19,6 +24,9 @@
920
921 set(LAUNCHER_SOURCES
922 upstart-app-launch.c
923+second-exec-core.c
924+upstart-app-launch-trace.c
925+"${CMAKE_SOURCE_DIR}/helpers-keyfile.c"
926 )
927
928 add_library(upstart-launcher SHARED ${LAUNCHER_SOURCES})
929@@ -34,6 +42,7 @@
930 ${GOBJECT2_LIBRARIES}
931 ${LIBUPSTART_LIBRARIES}
932 ${GIO2_LIBRARIES}
933+ ${LTTNG_LIBRARIES}
934 ${JSONGLIB_LIBRARIES}
935 -Wl,--no-undefined
936 )
937@@ -63,3 +72,26 @@
938 DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
939 )
940
941+##########################
942+# Introspection
943+##########################
944+
945+include(UseGObjectIntrospection)
946+
947+set(INTROSPECTION_GIRS)
948+set(_introspection_files ${LAUNCHER_HEADERS})
949+set(UpstartAppLaunch_2_gir "upstart-app-launch")
950+set(UpstartAppLaunch_2_gir_INCLUDES GObject-2.0)
951+
952+gir_get_cflags(_cflags)
953+set(UpstartAppLaunch_2_gir_CFLAGS ${c_flags})
954+set(UpstartAppLaunch_2_gir_LIBS upstart-app-launch)
955+
956+list_make_absolute(_abs_introspection_files _introspection_files "${CMAKE_CURRENT_SOURCE_DIR}/")
957+set(UpstartAppLaunch_2_gir_FILES ${_abs_introspection_files})
958+set(UpstartAppLaunch_2_gir_SCANNERFLAGS --c-include "upstart-app-launch.h")
959+set(UpstartAppLaunch_2_gir_EXPORT_PACKAGES "upstart-app-launch-${API_VERSION}")
960+
961+list(APPEND INTROSPECTION_GIRS UpstartAppLaunch-2.gir)
962+gir_add_introspections(INTROSPECTION_GIRS)
963+
964
965=== renamed file 'second-exec-core.c' => 'libupstart-app-launch/second-exec-core.c'
966--- second-exec-core.c 2013-12-06 10:38:35 +0000
967+++ libupstart-app-launch/second-exec-core.c 2014-02-11 03:28:22 +0000
968@@ -23,46 +23,49 @@
969 #include "libupstart-app-launch/upstart-app-launch.h"
970 #include "helpers.h"
971 #include "second-exec-core.h"
972-#include "second-exec-trace.h"
973-
974-/* Globals */
975-GPid app_pid = 0;
976-GMainLoop * mainloop = NULL;
977-guint connections_open = 0;
978-const gchar * appid = NULL;
979-const gchar * input_uris = NULL;
980-GVariant * app_data = NULL;
981-gchar * dbus_path = NULL;
982-guint64 unity_starttime = 0;
983-guint timer = 0;
984+#include "upstart-app-launch-trace.h"
985+
986+typedef struct {
987+ GDBusConnection * bus;
988+ gchar * appid;
989+ gchar * input_uris;
990+ GPid app_pid;
991+ guint connections_open;
992+ GVariant * app_data;
993+ gchar * dbus_path;
994+ guint64 unity_starttime;
995+ guint timer;
996+} second_exec_t;
997+
998+static void second_exec_complete (second_exec_t * data);
999
1000 /* Unity didn't respond in time, continue on */
1001 static gboolean
1002 timer_cb (gpointer user_data)
1003 {
1004- tracepoint(upstart_app_launch, second_exec_resume_timeout);
1005+ tracepoint(upstart_app_launch, second_exec_resume_timeout, ((second_exec_t *)user_data)->appid);
1006 g_warning("Unity didn't respond in 500ms to resume the app");
1007- g_main_loop_quit(mainloop);
1008+ second_exec_complete(user_data);
1009 return G_SOURCE_REMOVE;
1010 }
1011
1012 /* Lower the connection count and process if it gets to zero */
1013 static void
1014-connection_count_dec (void)
1015+connection_count_dec (second_exec_t * data)
1016 {
1017- tracepoint(upstart_app_launch, second_exec_connection_complete);
1018- connections_open--;
1019- if (connections_open == 0) {
1020+ tracepoint(upstart_app_launch, second_exec_connection_complete, data->appid);
1021+ data->connections_open--;
1022+ if (data->connections_open == 0) {
1023 g_debug("Finished finding connections");
1024 /* Check time here, either we've already heard from
1025 Unity and we should send the data to the app (quit) or
1026 we should wait some more */
1027- guint64 timespent = g_get_monotonic_time() - unity_starttime;
1028+ guint64 timespent = g_get_monotonic_time() - data->unity_starttime;
1029 if (timespent > 500 /* ms */ * 1000 /* ms to us */) {
1030- g_main_loop_quit(mainloop);
1031+ second_exec_complete(data);
1032 } else {
1033 g_debug("Timer Set");
1034- timer = g_timeout_add(500 - (timespent / 1000), timer_cb, NULL);
1035+ data->timer = g_timeout_add(500 - (timespent / 1000), timer_cb, data);
1036 }
1037 }
1038 return;
1039@@ -73,18 +76,20 @@
1040 static void
1041 unity_resume_cb (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
1042 {
1043+ second_exec_t * data = (second_exec_t *)user_data;
1044 g_debug("Unity Completed Resume");
1045- tracepoint(upstart_app_launch, second_exec_resume_complete);
1046+ tracepoint(upstart_app_launch, second_exec_resume_complete, data->appid);
1047
1048- if (timer != 0) {
1049- g_source_remove(timer);
1050+ if (data->timer != 0) {
1051+ g_source_remove(data->timer);
1052+ data->timer = 0;
1053 }
1054
1055- if (connections_open == 0) {
1056- g_main_loop_quit(mainloop);
1057+ if (data->connections_open == 0) {
1058+ second_exec_complete(data);
1059 } else {
1060 /* Make it look like we started *forever* ago */
1061- unity_starttime = 0;
1062+ data->unity_starttime = 0;
1063 }
1064
1065 return;
1066@@ -92,9 +97,9 @@
1067
1068 /* Turn the input string into something we can send to apps */
1069 static void
1070-parse_uris (void)
1071+parse_uris (second_exec_t * data)
1072 {
1073- if (app_data != NULL) {
1074+ if (data->app_data != NULL) {
1075 /* Already done */
1076 return;
1077 }
1078@@ -103,11 +108,11 @@
1079 gchar ** uri_split = NULL;
1080 GError * error = NULL;
1081
1082- g_shell_parse_argv(input_uris, NULL, &uri_split, &error);
1083+ g_shell_parse_argv(data->input_uris, NULL, &uri_split, &error);
1084
1085 if (uri_split == NULL || uri_split[0] == NULL || error != NULL) {
1086 if (error != NULL) {
1087- g_warning("Unable to parse URLs '%s': %s", input_uris, error->message);
1088+ g_warning("Unable to parse URLs '%s': %s", data->input_uris, error->message);
1089 g_error_free(error);
1090 }
1091
1092@@ -136,8 +141,8 @@
1093 g_variant_builder_add_value(&tuple, uris);
1094 g_variant_builder_add_value(&tuple, platform);
1095
1096- app_data = g_variant_builder_end(&tuple);
1097- g_variant_ref_sink(app_data);
1098+ data->app_data = g_variant_builder_end(&tuple);
1099+ g_variant_ref_sink(data->app_data);
1100
1101 return;
1102 }
1103@@ -149,14 +154,29 @@
1104 http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus
1105 */
1106 static void
1107-app_id_to_dbus_path (void)
1108+app_id_to_dbus_path (second_exec_t * data)
1109 {
1110- if (dbus_path != NULL) {
1111+ if (data->dbus_path != NULL) {
1112 return;
1113 }
1114
1115- dbus_path = nih_dbus_path(NULL, "", appid, NULL);
1116- g_debug("DBus Path: %s", dbus_path);
1117+ GString * str = g_string_sized_new(strlen(data->appid) + 2); /* base case, we just need a / and a null */
1118+ g_string_append_c(str, '/');
1119+
1120+ int i;
1121+ for (i = 0; data->appid[i] != '\0'; i++) {
1122+ if ((data->appid[i] >= 'a' && data->appid[i] <= 'z') ||
1123+ (data->appid[i] >= 'A' && data->appid[i] <= 'Z') ||
1124+ (data->appid[i] >= '0' && data->appid[i] <= '9' && i != 0)) {
1125+ g_string_append_c(str, data->appid[i]);
1126+ continue;
1127+ }
1128+
1129+ g_string_append_printf(str, "_%2x", data->appid[i]);
1130+ }
1131+
1132+ data->dbus_path = g_string_free(str, FALSE);
1133+ g_debug("DBus Path: %s", data->dbus_path);
1134
1135 return;
1136 }
1137@@ -167,68 +187,76 @@
1138 {
1139 GError * error = NULL;
1140
1141- tracepoint(upstart_app_launch, second_exec_app_contacted);
1142+ tracepoint(upstart_app_launch, second_exec_app_contacted, ((second_exec_t *)user_data)->appid);
1143
1144 g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
1145
1146 if (error != NULL) {
1147- tracepoint(upstart_app_launch, second_exec_app_error);
1148+ tracepoint(upstart_app_launch, second_exec_app_error, ((second_exec_t *)user_data)->appid);
1149 /* Mostly just to free the error, but printing for debugging */
1150 g_debug("Unable to send Open: %s", error->message);
1151 g_error_free(error);
1152 }
1153
1154- connection_count_dec();
1155+ connection_count_dec(user_data);
1156 return;
1157 }
1158
1159 /* Sends the Open message to the connection with the URIs we were given */
1160 static void
1161-contact_app (GDBusConnection * bus, const gchar * dbus_name)
1162+contact_app (GDBusConnection * bus, const gchar * dbus_name, second_exec_t * data)
1163 {
1164- tracepoint(upstart_app_launch, second_exec_contact_app);
1165+ tracepoint(upstart_app_launch, second_exec_contact_app, data->appid, dbus_name);
1166
1167- parse_uris();
1168- app_id_to_dbus_path();
1169+ parse_uris(data);
1170+ app_id_to_dbus_path(data);
1171
1172 /* Using the FD.o Application interface */
1173 g_dbus_connection_call(bus,
1174 dbus_name,
1175- dbus_path,
1176+ data->dbus_path,
1177 "org.freedesktop.Application",
1178 "Open",
1179- app_data,
1180+ data->app_data,
1181 NULL,
1182 G_DBUS_CALL_FLAGS_NONE,
1183 -1,
1184 NULL,
1185- send_open_cb, NULL);
1186+ send_open_cb, data);
1187
1188 g_debug("Sending Open request to: %s", dbus_name);
1189
1190 return;
1191 }
1192
1193+typedef struct {
1194+ gchar * name;
1195+ second_exec_t * data;
1196+} get_pid_t;
1197+
1198 /* Gets the PID for a connection, and if it matches the one we're looking
1199 for then it tries to send a message to that connection */
1200 static void
1201 get_pid_cb (GObject * object, GAsyncResult * res, gpointer user_data)
1202 {
1203- gchar * dbus_name = (gchar *)user_data;
1204+ get_pid_t * data = (get_pid_t *)user_data;
1205 GError * error = NULL;
1206 GVariant * vpid = NULL;
1207
1208- tracepoint(upstart_app_launch, second_exec_got_pid);
1209+ tracepoint(upstart_app_launch, second_exec_got_pid, data->data->appid, data->name);
1210
1211 vpid = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
1212
1213 if (error != NULL) {
1214- g_warning("Unable to query PID for dbus name '%s': %s", dbus_name, error->message);
1215+ g_warning("Unable to query PID for dbus name '%s': %s", data->name, error->message);
1216 g_error_free(error);
1217- g_free(dbus_name);
1218
1219 /* Lowering the connection count, this one is terminal, even if in error */
1220- connection_count_dec();
1221+ connection_count_dec(data->data);
1222+
1223+ g_free(data->name);
1224+ g_free(data);
1225+
1226 return;
1227 }
1228
1229@@ -236,22 +264,23 @@
1230 g_variant_get(vpid, "(u)", &pid);
1231 g_variant_unref(vpid);
1232
1233- if (pid == app_pid) {
1234+ if (pid == data->data->app_pid) {
1235 /* Trying to send a message to the connection */
1236- contact_app(G_DBUS_CONNECTION(object), dbus_name);
1237+ contact_app(G_DBUS_CONNECTION(object), data->name, data->data);
1238 } else {
1239 /* See if we can quit now */
1240- connection_count_dec();
1241+ connection_count_dec(data->data);
1242 }
1243
1244- g_free(dbus_name);
1245+ g_free(data->name);
1246+ g_free(data);
1247
1248 return;
1249 }
1250
1251 /* Starts to look for the PID and the connections for that PID */
1252 void
1253-find_appid_pid (GDBusConnection * session)
1254+find_appid_pid (GDBusConnection * session, second_exec_t * data)
1255 {
1256 GError * error = NULL;
1257
1258@@ -276,19 +305,21 @@
1259 return;
1260 }
1261
1262- tracepoint(upstart_app_launch, second_exec_got_dbus_names);
1263+ g_debug("Got bus names");
1264+ tracepoint(upstart_app_launch, second_exec_got_dbus_names, data->appid);
1265
1266 /* Next figure out what we're looking for (and if there is something to look for) */
1267 /* NOTE: We're getting the PID *after* the list of connections so
1268 that some new process can't come in, be the same PID as it's
1269 connection will not be in teh list we just got. */
1270- app_pid = upstart_app_launch_get_primary_pid(appid);
1271- if (app_pid == 0) {
1272- g_warning("Unable to find pid for app id '%s'", appid);
1273+ data->app_pid = upstart_app_launch_get_primary_pid(data->appid);
1274+ if (data->app_pid == 0) {
1275+ g_warning("Unable to find pid for app id '%s'", data->appid);
1276 return;
1277 }
1278
1279- tracepoint(upstart_app_launch, second_exec_got_primary_pid);
1280+ g_debug("Primary PID: %d", data->app_pid);
1281+ tracepoint(upstart_app_launch, second_exec_got_primary_pid, data->appid);
1282
1283 /* Get the names */
1284 GVariant * names = g_variant_get_child_value(listnames, 0);
1285@@ -301,8 +332,12 @@
1286 if (!g_dbus_is_unique_name(name)) {
1287 continue;
1288 }
1289+
1290+ get_pid_t * pid_data = g_new0(get_pid_t, 1);
1291+ pid_data->data = data;
1292+ pid_data->name = g_strdup(name);
1293
1294- tracepoint(upstart_app_launch, second_exec_request_pid);
1295+ tracepoint(upstart_app_launch, second_exec_request_pid, data->appid, pid_data->name);
1296
1297 /* Get the PIDs */
1298 g_dbus_connection_call(session,
1299@@ -315,9 +350,9 @@
1300 G_DBUS_CALL_FLAGS_NONE,
1301 -1,
1302 NULL,
1303- get_pid_cb, g_strdup(name));
1304+ get_pid_cb, pid_data);
1305
1306- connections_open++;
1307+ data->connections_open++;
1308 }
1309
1310 g_variant_unref(names);
1311@@ -329,10 +364,7 @@
1312 gboolean
1313 second_exec (const gchar * app_id, const gchar * appuris)
1314 {
1315- appid = app_id;
1316- input_uris = appuris;
1317-
1318- tracepoint(upstart_app_launch, second_exec_start);
1319+ tracepoint(upstart_app_launch, second_exec_start, app_id, appuris);
1320
1321 /* DBus tell us! */
1322 GError * error = NULL;
1323@@ -343,8 +375,11 @@
1324 return FALSE;
1325 }
1326
1327- /* Allocate main loop */
1328- mainloop = g_main_loop_new(NULL, FALSE);
1329+ /* Setup our continuation data */
1330+ second_exec_t * data = g_new0(second_exec_t, 1);
1331+ data->appid = g_strdup(app_id);
1332+ data->input_uris = g_strdup(appuris);
1333+ data->bus = session;
1334
1335 /* Set up listening for the unfrozen signal from Unity */
1336 g_dbus_connection_signal_subscribe(session,
1337@@ -352,12 +387,13 @@
1338 "com.canonical.UpstartAppLaunch", /* interface */
1339 "UnityResumeResponse", /* signal */
1340 "/", /* path */
1341- appid, /* arg0 */
1342+ app_id, /* arg0 */
1343 G_DBUS_SIGNAL_FLAGS_NONE,
1344- unity_resume_cb, mainloop,
1345+ unity_resume_cb, data,
1346 NULL); /* user data destroy */
1347
1348- tracepoint(upstart_app_launch, second_exec_emit_resume);
1349+ g_debug("Sending resume request");
1350+ tracepoint(upstart_app_launch, second_exec_emit_resume, app_id);
1351
1352 /* Send unfreeze to to Unity */
1353 g_dbus_connection_emit_signal(session,
1354@@ -365,43 +401,49 @@
1355 "/", /* path */
1356 "com.canonical.UpstartAppLaunch", /* interface */
1357 "UnityResumeRequest", /* signal */
1358- g_variant_new("(s)", appid),
1359+ g_variant_new("(s)", app_id),
1360 &error);
1361
1362 /* Now we start a race, we try to get to the point of knowing who
1363 to send things to, and Unity is unfrezing it. When both are
1364 done we can send something to the app */
1365- unity_starttime = g_get_monotonic_time();
1366+ data->unity_starttime = g_get_monotonic_time();
1367
1368 if (error != NULL) {
1369 /* On error let's not wait for Unity */
1370 g_warning("Unable to signal Unity: %s", error->message);
1371 g_error_free(error);
1372 error = NULL;
1373- unity_starttime = 0;
1374+ data->unity_starttime = 0;
1375 }
1376
1377 /* If we've got something to give out, start looking for how */
1378- if (input_uris != NULL) {
1379- find_appid_pid(session);
1380+ if (data->input_uris != NULL) {
1381+ find_appid_pid(session, data);
1382 }
1383
1384 /* Loop and wait for everything to align */
1385- if (connections_open > 0 || unity_starttime > 0) {
1386- g_main_loop_run(mainloop);
1387+ if (data->connections_open == 0 && data->unity_starttime == 0) {
1388+ second_exec_complete(data);
1389 }
1390- g_debug("Finishing main loop");
1391-
1392- tracepoint(upstart_app_launch, second_exec_emit_focus);
1393+
1394+ return TRUE;
1395+}
1396+
1397+static void
1398+second_exec_complete (second_exec_t * data)
1399+{
1400+ GError * error = NULL;
1401+ tracepoint(upstart_app_launch, second_exec_emit_focus, data->appid);
1402
1403 /* Now that we're done sending the info to the app, we can ask
1404 Unity to focus the application. */
1405- g_dbus_connection_emit_signal(session,
1406+ g_dbus_connection_emit_signal(data->bus,
1407 NULL, /* destination */
1408 "/", /* path */
1409 "com.canonical.UpstartAppLaunch", /* interface */
1410 "UnityFocusRequest", /* signal */
1411- g_variant_new("(s)", appid),
1412+ g_variant_new("(s)", data->appid),
1413 &error);
1414
1415 if (error != NULL) {
1416@@ -411,23 +453,23 @@
1417 }
1418
1419 /* Make sure the signal hits the bus */
1420- g_dbus_connection_flush_sync(session, NULL, NULL);
1421+ g_dbus_connection_flush_sync(data->bus, NULL, &error);
1422+ if (error != NULL) {
1423+ g_warning("Unable to flush session bus: %s", error->message);
1424+ g_error_free(error);
1425+ error = NULL;
1426+ }
1427+
1428+ tracepoint(upstart_app_launch, second_exec_finish, data->appid);
1429
1430 /* Clean up */
1431- if (app_data != NULL) {
1432- g_variant_unref(app_data);
1433- app_data = NULL;
1434- }
1435-
1436- g_main_loop_unref(mainloop);
1437- g_object_unref(session);
1438-
1439- if (dbus_path != NULL) {
1440- nih_free(dbus_path);
1441- dbus_path = NULL;
1442- }
1443-
1444- tracepoint(upstart_app_launch, second_exec_finish);
1445-
1446- return TRUE;
1447+ g_object_unref(data->bus);
1448+ if (data->app_data != NULL)
1449+ g_variant_unref(data->app_data);
1450+ g_free(data->appid);
1451+ g_free(data->input_uris);
1452+ g_free(data->dbus_path);
1453+ g_free(data);
1454+
1455+ return;
1456 }
1457
1458=== renamed file 'second-exec-core.h' => 'libupstart-app-launch/second-exec-core.h'
1459=== added file 'libupstart-app-launch/upstart-app-launch-trace.tp'
1460--- libupstart-app-launch/upstart-app-launch-trace.tp 1970-01-01 00:00:00 +0000
1461+++ libupstart-app-launch/upstart-app-launch-trace.tp 2014-02-11 03:28:22 +0000
1462@@ -0,0 +1,170 @@
1463+
1464+/*******************************
1465+ LibUAL start function
1466+ *******************************/
1467+TRACEPOINT_EVENT(upstart_app_launch, libual_start,
1468+ TP_ARGS(const char *, appid),
1469+ TP_FIELDS(
1470+ ctf_string(appid, appid)
1471+ )
1472+)
1473+TRACEPOINT_EVENT(upstart_app_launch, libual_determine_type,
1474+ TP_ARGS(const char *, appid, const char *, type),
1475+ TP_FIELDS(
1476+ ctf_string(appid, appid)
1477+ ctf_string(type, type)
1478+ )
1479+)
1480+TRACEPOINT_EVENT(upstart_app_launch, libual_job_path_determined,
1481+ TP_ARGS(const char *, appid, const char *, job_path),
1482+ TP_FIELDS(
1483+ ctf_string(appid, appid)
1484+ ctf_string(job_path, job_path)
1485+ )
1486+)
1487+TRACEPOINT_EVENT(upstart_app_launch, libual_start_message_sent,
1488+ TP_ARGS(const char *, appid),
1489+ TP_FIELDS(
1490+ ctf_string(appid, appid)
1491+ )
1492+)
1493+TRACEPOINT_EVENT(upstart_app_launch, libual_start_message_callback,
1494+ TP_ARGS(const char *, appid),
1495+ TP_FIELDS(
1496+ ctf_string(appid, appid)
1497+ )
1498+)
1499+
1500+/*******************************
1501+ LibUAL observers
1502+ *******************************/
1503+
1504+TRACEPOINT_EVENT(upstart_app_launch, observer_start,
1505+ TP_ARGS(const char *, type),
1506+ TP_FIELDS(
1507+ ctf_string(type, type)
1508+ )
1509+)
1510+TRACEPOINT_EVENT(upstart_app_launch, observer_finish,
1511+ TP_ARGS(const char *, type),
1512+ TP_FIELDS(
1513+ ctf_string(type, type)
1514+ )
1515+)
1516+
1517+
1518+/*******************************
1519+ Second Exec tracking
1520+ *******************************/
1521+TRACEPOINT_EVENT(upstart_app_launch, second_exec_start,
1522+ TP_ARGS(const char *, appid, const char *, appuris),
1523+ TP_FIELDS(
1524+ ctf_string(appid, appid)
1525+ ctf_string(appuris, appuris)
1526+ )
1527+)
1528+TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_resume,
1529+ TP_ARGS(const char *, appid),
1530+ TP_FIELDS(
1531+ ctf_string(appid, appid)
1532+ )
1533+)
1534+TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_complete,
1535+ TP_ARGS(const char *, appid),
1536+ TP_FIELDS(
1537+ ctf_string(appid, appid)
1538+ )
1539+)
1540+TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_timeout,
1541+ TP_ARGS(const char *, appid),
1542+ TP_FIELDS(
1543+ ctf_string(appid, appid)
1544+ )
1545+)
1546+TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_focus,
1547+ TP_ARGS(const char *, appid),
1548+ TP_FIELDS(
1549+ ctf_string(appid, appid)
1550+ )
1551+)
1552+TRACEPOINT_EVENT(upstart_app_launch, second_exec_finish,
1553+ TP_ARGS(const char *, appid),
1554+ TP_FIELDS(
1555+ ctf_string(appid, appid)
1556+ )
1557+)
1558+TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_dbus_names,
1559+ TP_ARGS(const char *, appid),
1560+ TP_FIELDS(
1561+ ctf_string(appid, appid)
1562+ )
1563+)
1564+TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_primary_pid,
1565+ TP_ARGS(const char *, appid),
1566+ TP_FIELDS(
1567+ ctf_string(appid, appid)
1568+ )
1569+)
1570+TRACEPOINT_EVENT(upstart_app_launch, second_exec_request_pid,
1571+ TP_ARGS(const char *, appid, const char *, dbus_name),
1572+ TP_FIELDS(
1573+ ctf_string(appid, appid)
1574+ ctf_string(dbus_name, dbus_name)
1575+ )
1576+)
1577+TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_pid,
1578+ TP_ARGS(const char *, appid, const char *, dbus_name),
1579+ TP_FIELDS(
1580+ ctf_string(appid, appid)
1581+ ctf_string(dbus_name, dbus_name)
1582+ )
1583+)
1584+TRACEPOINT_EVENT(upstart_app_launch, second_exec_contact_app,
1585+ TP_ARGS(const char *, appid, const char *, dbus_name),
1586+ TP_FIELDS(
1587+ ctf_string(appid, appid)
1588+ ctf_string(dbus_name, dbus_name)
1589+ )
1590+)
1591+TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_contacted,
1592+ TP_ARGS(const char *, appid),
1593+ TP_FIELDS(
1594+ ctf_string(appid, appid)
1595+ )
1596+)
1597+TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_error,
1598+ TP_ARGS(const char *, appid),
1599+ TP_FIELDS(
1600+ ctf_string(appid, appid)
1601+ )
1602+)
1603+TRACEPOINT_EVENT(upstart_app_launch, second_exec_connection_complete,
1604+ TP_ARGS(const char *, appid),
1605+ TP_FIELDS(
1606+ ctf_string(appid, appid)
1607+ )
1608+)
1609+
1610+/*******************************
1611+ Desktop File Single Instance
1612+ *******************************/
1613+TRACEPOINT_EVENT(upstart_app_launch, desktop_single_start,
1614+ TP_ARGS(const char *, appid),
1615+ TP_FIELDS(
1616+ ctf_string(appid, appid)
1617+ )
1618+)
1619+TRACEPOINT_EVENT(upstart_app_launch, desktop_single_found,
1620+ TP_ARGS(const char *, appid),
1621+ TP_FIELDS(
1622+ ctf_string(appid, appid)
1623+ )
1624+)
1625+TRACEPOINT_EVENT(upstart_app_launch, desktop_single_finished,
1626+ TP_ARGS(const char *, appid, const char *, apptype),
1627+ TP_FIELDS(
1628+ ctf_string(appid, appid)
1629+ ctf_string(apptype, apptype)
1630+ )
1631+)
1632+
1633
1634=== modified file 'libupstart-app-launch/upstart-app-launch.c'
1635--- libupstart-app-launch/upstart-app-launch.c 2014-01-29 02:19:27 +0000
1636+++ libupstart-app-launch/upstart-app-launch.c 2014-02-11 03:28:22 +0000
1637@@ -20,53 +20,16 @@
1638 #include "upstart-app-launch.h"
1639 #include <json-glib/json-glib.h>
1640 #include <upstart.h>
1641-#include <nih/alloc.h>
1642-#include <nih/error.h>
1643 #include <gio/gio.h>
1644 #include <string.h>
1645
1646-static void apps_for_job (NihDBusProxy * upstart, const gchar * name, GArray * apps, gboolean truncate_legacy);
1647+#include "upstart-app-launch-trace.h"
1648+#include "second-exec-core.h"
1649+#include "../helpers.h"
1650+
1651+static void apps_for_job (GDBusConnection * con, const gchar * name, GArray * apps, gboolean truncate_legacy);
1652 static void free_helper (gpointer value);
1653
1654-static NihDBusProxy *
1655-nih_proxy_create (void)
1656-{
1657- NihDBusProxy * upstart;
1658- DBusConnection * conn;
1659- DBusError error;
1660- const gchar * bus_name = NULL;
1661-
1662- dbus_error_init(&error);
1663-
1664- conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
1665- bus_name = "com.ubuntu.Upstart";
1666-
1667- if (conn == NULL) {
1668- g_warning("Unable to connect to the Upstart Session: %s", error.message);
1669- dbus_error_free(&error);
1670- return NULL;
1671- }
1672-
1673- dbus_error_free(&error);
1674-
1675- upstart = nih_dbus_proxy_new(NULL, conn,
1676- bus_name,
1677- DBUS_PATH_UPSTART,
1678- NULL, NULL);
1679-
1680- if (upstart == NULL) {
1681- g_warning("Unable to build proxy to Upstart");
1682- dbus_connection_unref(conn);
1683- return NULL;
1684- }
1685-
1686- dbus_connection_unref(conn);
1687-
1688- upstart->auto_start = FALSE;
1689-
1690- return upstart;
1691-}
1692-
1693 /* Function to take the urls and escape them so that they can be
1694 parsed on the other side correctly. */
1695 static gchar *
1696@@ -87,83 +50,261 @@
1697 return urisjoin;
1698 }
1699
1700+typedef struct {
1701+ gchar * appid;
1702+ gchar * uris;
1703+} app_start_t;
1704+
1705+static void
1706+application_start_cb (GObject * obj, GAsyncResult * res, gpointer user_data)
1707+{
1708+ app_start_t * data = (app_start_t *)user_data;
1709+ GError * error = NULL;
1710+ GVariant * result = NULL;
1711+
1712+ tracepoint(upstart_app_launch, libual_start_message_callback, data->appid);
1713+ g_debug("Started Message Callback: %s", data->appid);
1714+
1715+ result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
1716+
1717+ if (result != NULL)
1718+ g_variant_unref(result);
1719+
1720+ if (error != NULL) {
1721+ if (g_dbus_error_is_remote_error(error)) {
1722+ gchar * remote_error = g_dbus_error_get_remote_error(error);
1723+ g_debug("Remote error: %s", remote_error);
1724+ if (g_strcmp0(remote_error, "com.ubuntu.Upstart0_6.Error.AlreadyStarted") == 0) {
1725+ second_exec(data->appid, data->uris);
1726+ }
1727+
1728+ g_free(remote_error);
1729+ } else {
1730+ g_warning("Unable to emit event to start application: %s", error->message);
1731+ }
1732+ g_error_free(error);
1733+ }
1734+
1735+ g_free(data->appid);
1736+ g_free(data->uris);
1737+ g_free(data);
1738+}
1739+
1740+/* Get the path of the job from Upstart, if we've got it already, we'll just
1741+ use the cache of the value */
1742+static const gchar *
1743+get_jobpath (GDBusConnection * con, const gchar * jobname)
1744+{
1745+ gchar * cachepath = g_strdup_printf("upstart-app-lauch-job-path-cache-%s", jobname);
1746+ gpointer cachedata = g_object_get_data(G_OBJECT(con), cachepath);
1747+
1748+ if (cachedata != NULL) {
1749+ g_free(cachepath);
1750+ return cachedata;
1751+ }
1752+
1753+ GError * error = NULL;
1754+ GVariant * job_path_variant = g_dbus_connection_call_sync(con,
1755+ DBUS_SERVICE_UPSTART,
1756+ DBUS_PATH_UPSTART,
1757+ DBUS_INTERFACE_UPSTART,
1758+ "GetJobByName",
1759+ g_variant_new("(s)", jobname),
1760+ G_VARIANT_TYPE("(o)"),
1761+ G_DBUS_CALL_FLAGS_NONE,
1762+ -1, /* timeout: default */
1763+ NULL, /* cancelable */
1764+ &error);
1765+
1766+ if (error != NULL) {
1767+ g_warning("Unable to find job '%s': %s", jobname, error->message);
1768+ g_error_free(error);
1769+ g_free(cachepath);
1770+ return NULL;
1771+ }
1772+
1773+ gchar * job_path = NULL;
1774+ g_variant_get(job_path_variant, "(o)", &job_path);
1775+ g_variant_unref(job_path_variant);
1776+
1777+ g_object_set_data_full(G_OBJECT(con), cachepath, job_path, g_free);
1778+ g_free(cachepath);
1779+
1780+ return job_path;
1781+}
1782+
1783+/* Check to see if a legacy app wants us to manage whether they're
1784+ single instance or not */
1785+static gboolean
1786+legacy_single_instance (const gchar * appid)
1787+{
1788+ tracepoint(upstart_app_launch, desktop_single_start, appid);
1789+
1790+ GKeyFile * keyfile = keyfile_for_appid(appid, NULL);
1791+
1792+ if (keyfile == NULL) {
1793+ g_error("Unable to find keyfile for application '%s'", appid);
1794+ return FALSE;
1795+ }
1796+
1797+ tracepoint(upstart_app_launch, desktop_single_found, appid);
1798+
1799+ gboolean singleinstance = FALSE;
1800+
1801+ if (g_key_file_has_key(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", NULL)) {
1802+ GError * error = NULL;
1803+
1804+ singleinstance = g_key_file_get_boolean(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", &error);
1805+
1806+ if (error != NULL) {
1807+ g_warning("Unable to get single instance key for app '%s': %s", appid, error->message);
1808+ g_error_free(error);
1809+ /* Ensure that if we got an error, we assume standard case */
1810+ singleinstance = FALSE;
1811+ }
1812+ }
1813+
1814+ g_key_file_free(keyfile);
1815+
1816+ tracepoint(upstart_app_launch, desktop_single_finished, appid, singleinstance ? "single" : "unmanaged");
1817+
1818+ return singleinstance;
1819+}
1820+
1821 gboolean
1822 upstart_app_launch_start_application (const gchar * appid, const gchar * const * uris)
1823 {
1824- NihDBusProxy * proxy = NULL;
1825-
1826- proxy = nih_proxy_create();
1827- if (proxy == NULL) {
1828+ g_return_val_if_fail(appid != NULL, FALSE);
1829+
1830+ tracepoint(upstart_app_launch, libual_start, appid);
1831+
1832+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
1833+ g_return_val_if_fail(con != NULL, FALSE);
1834+
1835+ /* Determine whether it's a click package by looking for the symlink
1836+ that is created by the desktop hook */
1837+ gchar * appiddesktop = g_strdup_printf("%s.desktop", appid);
1838+ gchar * click_link = NULL;
1839+ const gchar * link_farm_dir = g_getenv("UPSTART_APP_LAUNCH_LINK_FARM");
1840+ if (G_LIKELY(link_farm_dir == NULL)) {
1841+ click_link = g_build_filename(g_get_home_dir(), ".cache", "upstart-app-launch", "desktop", appiddesktop, NULL);
1842+ } else {
1843+ click_link = g_build_filename(link_farm_dir, appiddesktop, NULL);
1844+ }
1845+ g_free(appiddesktop);
1846+ gboolean click = g_file_test(click_link, G_FILE_TEST_EXISTS);
1847+ g_free(click_link);
1848+
1849+ tracepoint(upstart_app_launch, libual_determine_type, appid, click ? "click" : "legacy");
1850+
1851+ /* Figure out the DBus path for the job */
1852+ const gchar * jobpath = NULL;
1853+ if (click) {
1854+ jobpath = get_jobpath(con, "application-click");
1855+ } else {
1856+ jobpath = get_jobpath(con, "application-legacy");
1857+ }
1858+
1859+ if (jobpath == NULL)
1860 return FALSE;
1861- }
1862-
1863- gchar * env_appid = g_strdup_printf("APP_ID=%s", appid);
1864- gchar * env_uris = NULL;
1865+
1866+ tracepoint(upstart_app_launch, libual_job_path_determined, appid, jobpath);
1867+
1868+ /* Callback data */
1869+ app_start_t * app_start_data = g_new0(app_start_t, 1);
1870+ app_start_data->appid = g_strdup(appid);
1871+
1872+ /* Build up our environment */
1873+ GVariantBuilder builder;
1874+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
1875+
1876+ g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
1877+
1878+ g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("APP_ID=%s", appid)));
1879
1880 if (uris != NULL) {
1881 gchar * urisjoin = app_uris_string(uris);
1882- env_uris = g_strdup_printf("APP_URIS=%s", urisjoin);
1883- g_free(urisjoin);
1884- }
1885-
1886- gchar * env[3];
1887- env[0] = env_appid;
1888- env[1] = env_uris;
1889- env[2] = NULL;
1890-
1891- gboolean retval = TRUE;
1892- if (upstart_emit_event_sync(NULL, proxy, "application-start", env, 0) != 0) {
1893- g_warning("Unable to emit signal 'application-start'");
1894- retval = FALSE;
1895- }
1896-
1897- g_free(env_appid);
1898- g_free(env_uris);
1899- nih_unref(proxy, NULL);
1900-
1901- return retval;
1902+ gchar * urienv = g_strdup_printf("APP_URIS=%s", urisjoin);
1903+ app_start_data->uris = urisjoin;
1904+ g_variant_builder_add_value(&builder, g_variant_new_take_string(urienv));
1905+ }
1906+
1907+ if (!click) {
1908+ if (legacy_single_instance(appid)) {
1909+ g_variant_builder_add_value(&builder, g_variant_new_string("INSTANCE_ID="));
1910+ } else {
1911+ gchar * instanceid = g_strdup_printf("INSTANCE_ID=%" G_GUINT64_FORMAT, g_get_real_time());
1912+ g_variant_builder_add_value(&builder, g_variant_new_take_string(instanceid));
1913+ }
1914+ }
1915+
1916+ g_variant_builder_close(&builder);
1917+ g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
1918+
1919+ /* Call the job start function */
1920+ g_dbus_connection_call(con,
1921+ DBUS_SERVICE_UPSTART,
1922+ jobpath,
1923+ DBUS_INTERFACE_UPSTART_JOB,
1924+ "Start",
1925+ g_variant_builder_end(&builder),
1926+ NULL,
1927+ G_DBUS_CALL_FLAGS_NONE,
1928+ -1,
1929+ NULL, /* cancelable */
1930+ application_start_cb,
1931+ app_start_data);
1932+
1933+ tracepoint(upstart_app_launch, libual_start_message_sent, appid);
1934+
1935+ g_object_unref(con);
1936+
1937+ return TRUE;
1938 }
1939
1940 static void
1941-stop_job (NihDBusProxy * upstart, const gchar * jobname, const gchar * appname, const gchar * instanceid)
1942+stop_job (GDBusConnection * con, const gchar * jobname, const gchar * appname, const gchar * instanceid)
1943 {
1944 g_debug("Stopping job %s app_id %s instance_id %s", jobname, appname, instanceid);
1945- nih_local char * job_path = NULL;
1946- if (upstart_get_job_by_name_sync(NULL, upstart, jobname, &job_path) != 0) {
1947- g_warning("Unable to find job '%s'", jobname);
1948- return;
1949- }
1950-
1951- NihDBusProxy * job_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
1952- upstart->name,
1953- job_path,
1954- NULL, NULL);
1955-
1956- if (job_proxy == NULL) {
1957- g_warning("Unable to build proxy to Job '%s'", jobname);
1958- return;
1959- }
1960-
1961- gchar * app = g_strdup_printf("APP_ID=%s", appname);
1962- gchar * inst = NULL;
1963+
1964+ const gchar * job_path = get_jobpath(con, jobname);
1965+ if (job_path == NULL)
1966+ return;
1967+
1968+ GVariantBuilder builder;
1969+ g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
1970+ g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
1971+
1972+ g_variant_builder_add_value(&builder,
1973+ g_variant_new_take_string(g_strdup_printf("APP_ID=%s", appname)));
1974
1975 if (instanceid != NULL) {
1976- inst = g_strdup_printf("INSTANCE_ID=%s", instanceid);
1977- }
1978-
1979- gchar * env[3] = {
1980- app,
1981- inst,
1982- NULL
1983- };
1984-
1985- if (job_class_stop_sync(NULL, job_proxy, env, 0) != 0) {
1986- g_warning("Unable to stop job %s app %s instance %s", jobname, appname, instanceid);
1987- }
1988-
1989- g_free(app);
1990- g_free(inst);
1991- nih_unref(job_proxy, NULL);
1992+ g_variant_builder_add_value(&builder,
1993+ g_variant_new_take_string(g_strdup_printf("INSTANCE_ID=%s", instanceid)));
1994+ }
1995+
1996+ g_variant_builder_close(&builder);
1997+ g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); /* wait */
1998+
1999+ GError * error = NULL;
2000+ GVariant * stop_variant = g_dbus_connection_call_sync(con,
2001+ DBUS_SERVICE_UPSTART,
2002+ job_path,
2003+ DBUS_INTERFACE_UPSTART_JOB,
2004+ "Stop",
2005+ g_variant_builder_end(&builder),
2006+ NULL,
2007+ G_DBUS_CALL_FLAGS_NONE,
2008+ -1, /* timeout: default */
2009+ NULL, /* cancelable */
2010+ &error);
2011+
2012+ if (error != NULL) {
2013+ g_warning("Unable to stop job %s app_id %s instance_id %s: %s", jobname, appname, instanceid, error->message);
2014+ g_error_free(error);
2015+ }
2016+
2017+ g_variant_unref(stop_variant);
2018 }
2019
2020 static void
2021@@ -176,25 +317,24 @@
2022 gboolean
2023 upstart_app_launch_stop_application (const gchar * appid)
2024 {
2025+ g_return_val_if_fail(appid != NULL, FALSE);
2026+
2027+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2028+ g_return_val_if_fail(con != NULL, FALSE);
2029+
2030 gboolean found = FALSE;
2031 int i;
2032- NihDBusProxy * proxy = NULL;
2033-
2034- proxy = nih_proxy_create();
2035- if (proxy == NULL) {
2036- return FALSE;
2037- }
2038
2039 GArray * apps = g_array_new(TRUE, TRUE, sizeof(gchar *));
2040 g_array_set_clear_func(apps, free_helper);
2041
2042 /* Look through the click jobs and see if any match. There can
2043 only be one instance for each ID in the click world */
2044- apps_for_job(proxy, "application-click", apps, FALSE);
2045+ apps_for_job(con, "application-click", apps, FALSE);
2046 for (i = 0; i < apps->len; i++) {
2047 const gchar * array_id = g_array_index(apps, const gchar *, i);
2048 if (g_strcmp0(array_id, appid) == 0) {
2049- stop_job(proxy, "application-click", appid, NULL);
2050+ stop_job(con, "application-click", appid, NULL);
2051 found = TRUE;
2052 break; /* There can be only one with click */
2053 }
2054@@ -206,20 +346,20 @@
2055 /* Look through the legacy apps. Trickier because we know that there
2056 can be many instances of the legacy jobs out there, so we might
2057 have to kill more than one of them. */
2058- apps_for_job(proxy, "application-legacy", apps, FALSE);
2059+ apps_for_job(con, "application-legacy", apps, FALSE);
2060 gchar * appiddash = g_strdup_printf("%s-", appid); /* Probably could go RegEx here, but let's start with just a prefix lookup */
2061 for (i = 0; i < apps->len; i++) {
2062 const gchar * array_id = g_array_index(apps, const gchar *, i);
2063 if (g_str_has_prefix(array_id, appiddash)) {
2064 gchar * instanceid = g_strrstr(array_id, "-");
2065- stop_job(proxy, "application-legacy", appid, &(instanceid[1]));
2066+ stop_job(con, "application-legacy", appid, &(instanceid[1]));
2067 found = TRUE;
2068 }
2069 }
2070 g_free(appiddash);
2071
2072 g_array_free(apps, TRUE);
2073- nih_unref(proxy, NULL);
2074+ g_object_unref(con);
2075
2076 return found;
2077 }
2078@@ -255,18 +395,33 @@
2079 gpointer user_data;
2080 };
2081
2082+/* The data we keep for each failed observer */
2083+typedef struct _failed_observer_t failed_observer_t;
2084+struct _failed_observer_t {
2085+ GDBusConnection * conn;
2086+ guint sighandle;
2087+ upstart_app_launch_app_failed_observer_t func;
2088+ gpointer user_data;
2089+};
2090+
2091 /* The lists of Observers */
2092 static GList * starting_array = NULL;
2093 static GList * started_array = NULL;
2094 static GList * stop_array = NULL;
2095 static GList * focus_array = NULL;
2096 static GList * resume_array = NULL;
2097+static GList * failed_array = NULL;
2098
2099 static void
2100 observer_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
2101 {
2102 observer_t * observer = (observer_t *)user_data;
2103
2104+ const gchar * signalname = NULL;
2105+ g_variant_get_child(params, 0, "&s", &signalname);
2106+
2107+ tracepoint(upstart_app_launch, observer_start, signalname);
2108+
2109 gchar * env = NULL;
2110 GVariant * envs = g_variant_get_child_value(params, 1);
2111 GVariantIter iter;
2112@@ -300,6 +455,8 @@
2113 observer->func(instance, observer->user_data);
2114 }
2115
2116+ tracepoint(upstart_app_launch, observer_finish, signalname);
2117+
2118 g_free(instance);
2119 }
2120
2121@@ -388,10 +545,14 @@
2122 observer_t * observer = (observer_t *)user_data;
2123 const gchar * appid = NULL;
2124
2125+ tracepoint(upstart_app_launch, observer_start, "focus");
2126+
2127 if (observer->func != NULL) {
2128 g_variant_get(params, "(&s)", &appid);
2129 observer->func(appid, observer->user_data);
2130 }
2131+
2132+ tracepoint(upstart_app_launch, observer_finish, "focus");
2133 }
2134
2135 gboolean
2136@@ -404,6 +565,8 @@
2137 static void
2138 resume_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
2139 {
2140+ tracepoint(upstart_app_launch, observer_start, "resume");
2141+
2142 focus_signal_cb(conn, sender, object, interface, signal, params, user_data);
2143
2144 GError * error = NULL;
2145@@ -419,6 +582,8 @@
2146 g_warning("Unable to emit response signal: %s", error->message);
2147 g_error_free(error);
2148 }
2149+
2150+ tracepoint(upstart_app_launch, observer_finish, "resume");
2151 }
2152
2153 gboolean
2154@@ -431,6 +596,8 @@
2155 static void
2156 starting_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
2157 {
2158+ tracepoint(upstart_app_launch, observer_start, "starting");
2159+
2160 focus_signal_cb(conn, sender, object, interface, signal, params, user_data);
2161
2162 GError * error = NULL;
2163@@ -446,6 +613,8 @@
2164 g_warning("Unable to emit response signal: %s", error->message);
2165 g_error_free(error);
2166 }
2167+
2168+ tracepoint(upstart_app_launch, observer_finish, "starting");
2169 }
2170
2171 gboolean
2172@@ -454,10 +623,63 @@
2173 return add_session_generic(observer, user_data, "UnityStartingBroadcast", &starting_array, starting_signal_cb);
2174 }
2175
2176+/* Handle the failed signal when it occurs, call the observer */
2177+static void
2178+failed_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
2179+{
2180+ failed_observer_t * observer = (failed_observer_t *)user_data;
2181+ const gchar * appid = NULL;
2182+ const gchar * typestr = NULL;
2183+
2184+ tracepoint(upstart_app_launch, observer_start, "failed");
2185+
2186+ if (observer->func != NULL) {
2187+ upstart_app_launch_app_failed_t type = UPSTART_APP_LAUNCH_APP_FAILED_CRASH;
2188+ g_variant_get(params, "(&s&s)", &appid, &typestr);
2189+
2190+ if (g_strcmp0("crash", typestr) == 0) {
2191+ type = UPSTART_APP_LAUNCH_APP_FAILED_CRASH;
2192+ } else if (g_strcmp0("start-failure", typestr) == 0) {
2193+ type = UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE;
2194+ } else {
2195+ g_warning("Application failure type '%s' unknown, reporting as a crash", typestr);
2196+ }
2197+
2198+ observer->func(appid, type, observer->user_data);
2199+ }
2200+
2201+ tracepoint(upstart_app_launch, observer_finish, "failed");
2202+}
2203+
2204 gboolean
2205 upstart_app_launch_observer_add_app_failed (upstart_app_launch_app_failed_observer_t observer, gpointer user_data)
2206 {
2207- return FALSE;
2208+ GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2209+
2210+ if (conn == NULL) {
2211+ return FALSE;
2212+ }
2213+
2214+ failed_observer_t * observert = g_new0(failed_observer_t, 1);
2215+
2216+ observert->conn = conn;
2217+ observert->func = observer;
2218+ observert->user_data = user_data;
2219+
2220+ failed_array = g_list_prepend(failed_array, observert);
2221+
2222+ observert->sighandle = g_dbus_connection_signal_subscribe(conn,
2223+ NULL, /* sender */
2224+ "com.canonical.UpstartAppLaunch", /* interface */
2225+ "ApplicationFailed", /* signal */
2226+ "/", /* path */
2227+ NULL, /* arg0 */
2228+ G_DBUS_SIGNAL_FLAGS_NONE,
2229+ failed_signal_cb,
2230+ observert,
2231+ NULL); /* user data destroy */
2232+
2233+ return TRUE;
2234 }
2235
2236 static gboolean
2237@@ -520,167 +742,234 @@
2238 gboolean
2239 upstart_app_launch_observer_delete_app_failed (upstart_app_launch_app_failed_observer_t observer, gpointer user_data)
2240 {
2241- return FALSE;
2242+ failed_observer_t * observert = NULL;
2243+ GList * look;
2244+
2245+ for (look = failed_array; look != NULL; look = g_list_next(look)) {
2246+ observert = (failed_observer_t *)look->data;
2247+
2248+ if (observert->func == observer && observert->user_data == user_data) {
2249+ break;
2250+ }
2251+ }
2252+
2253+ if (look == NULL) {
2254+ return FALSE;
2255+ }
2256+
2257+ g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);
2258+ g_object_unref(observert->conn);
2259+
2260+ g_free(observert);
2261+ failed_array = g_list_delete_link(failed_array, look);
2262+
2263+ return TRUE;
2264+}
2265+
2266+typedef void (*per_instance_func_t) (GDBusConnection * con, GVariant * prop_dict, gpointer user_data);
2267+
2268+static void
2269+foreach_job_instance (GDBusConnection * con, const gchar * jobname, per_instance_func_t func, gpointer user_data)
2270+{
2271+ const gchar * job_path = get_jobpath(con, jobname);
2272+ if (job_path == NULL)
2273+ return;
2274+
2275+ GError * error = NULL;
2276+ GVariant * instance_tuple = g_dbus_connection_call_sync(con,
2277+ DBUS_SERVICE_UPSTART,
2278+ job_path,
2279+ DBUS_INTERFACE_UPSTART_JOB,
2280+ "GetAllInstances",
2281+ NULL,
2282+ G_VARIANT_TYPE("(ao)"),
2283+ G_DBUS_CALL_FLAGS_NONE,
2284+ -1, /* timeout: default */
2285+ NULL, /* cancelable */
2286+ &error);
2287+
2288+ if (error != NULL) {
2289+ g_warning("Unable to get instances of job '%s': %s", jobname, error->message);
2290+ g_error_free(error);
2291+ return;
2292+ }
2293+
2294+ GVariant * instance_list = g_variant_get_child_value(instance_tuple, 0);
2295+ g_variant_unref(instance_tuple);
2296+
2297+ GVariantIter instance_iter;
2298+ g_variant_iter_init(&instance_iter, instance_list);
2299+ const gchar * instance_path = NULL;
2300+
2301+ while (g_variant_iter_loop(&instance_iter, "&o", &instance_path)) {
2302+ GVariant * props_tuple = g_dbus_connection_call_sync(con,
2303+ DBUS_SERVICE_UPSTART,
2304+ instance_path,
2305+ "org.freedesktop.DBus.Properties",
2306+ "GetAll",
2307+ g_variant_new("(s)", DBUS_INTERFACE_UPSTART_INSTANCE),
2308+ G_VARIANT_TYPE("(a{sv})"),
2309+ G_DBUS_CALL_FLAGS_NONE,
2310+ -1, /* timeout: default */
2311+ NULL, /* cancelable */
2312+ &error);
2313+
2314+ if (error != NULL) {
2315+ g_warning("Unable to name of instance '%s': %s", instance_path, error->message);
2316+ g_error_free(error);
2317+ error = NULL;
2318+ continue;
2319+ }
2320+
2321+ GVariant * props_dict = g_variant_get_child_value(props_tuple, 0);
2322+
2323+ func(con, props_dict, user_data);
2324+
2325+ g_variant_unref(props_dict);
2326+ g_variant_unref(props_tuple);
2327+
2328+ }
2329+
2330+ g_variant_unref(instance_list);
2331+}
2332+
2333+typedef struct {
2334+ GArray * apps;
2335+ gboolean truncate_legacy;
2336+ const gchar * jobname;
2337+} apps_for_job_t;
2338+
2339+static void
2340+apps_for_job_instance (GDBusConnection * con, GVariant * props_dict, gpointer user_data)
2341+{
2342+ GVariant * namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
2343+ if (namev == NULL) {
2344+ return;
2345+ }
2346+
2347+ apps_for_job_t * data = (apps_for_job_t *)user_data;
2348+ gchar * instance_name = g_variant_dup_string(namev, NULL);
2349+ g_variant_unref(namev);
2350+
2351+ if (data->truncate_legacy && g_strcmp0(data->jobname, "application-legacy") == 0) {
2352+ gchar * last_dash = g_strrstr(instance_name, "-");
2353+ if (last_dash != NULL) {
2354+ last_dash[0] = '\0';
2355+ }
2356+ }
2357+
2358+ g_array_append_val(data->apps, instance_name);
2359 }
2360
2361 /* Get all the instances for a given job name */
2362 static void
2363-apps_for_job (NihDBusProxy * upstart, const gchar * name, GArray * apps, gboolean truncate_legacy)
2364+apps_for_job (GDBusConnection * con, const gchar * jobname, GArray * apps, gboolean truncate_legacy)
2365 {
2366- nih_local char * job_path = NULL;
2367- if (upstart_get_job_by_name_sync(NULL, upstart, name, &job_path) != 0) {
2368- g_warning("Unable to find job '%s'", name);
2369- return;
2370- }
2371-
2372- nih_local NihDBusProxy * job_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
2373- upstart->name,
2374- job_path,
2375- NULL, NULL);
2376-
2377- if (job_proxy == NULL) {
2378- g_warning("Unable to build proxy to Job '%s'", name);
2379- return;
2380- }
2381-
2382- nih_local char ** instances;
2383- if (job_class_get_all_instances_sync(NULL, job_proxy, &instances) != 0) {
2384- NihError * error = nih_error_get();
2385- g_warning("Unable to get instances for job '%s': %s", name, error->message);
2386- nih_free(error);
2387- return;
2388- }
2389-
2390- int jobnum;
2391- for (jobnum = 0; instances[jobnum] != NULL; jobnum++) {
2392- NihDBusProxy * instance_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
2393- upstart->name,
2394- instances[jobnum],
2395- NULL, NULL);
2396-
2397- nih_local char * instance_name = NULL;
2398- if (job_get_name_sync(NULL, instance_proxy, &instance_name) == 0) {
2399- gchar * dup = g_strdup(instance_name);
2400-
2401- if (truncate_legacy && g_strcmp0(name, "application-legacy") == 0) {
2402- gchar * last_dash = g_strrstr(dup, "-");
2403- if (last_dash != NULL) {
2404- last_dash[0] = '\0';
2405- }
2406- }
2407-
2408- g_array_append_val(apps, dup);
2409- } else {
2410- g_warning("Unable to get name for instance '%s' of job '%s'", instances[jobnum], name);
2411- }
2412-
2413- nih_unref(instance_proxy, NULL);
2414- }
2415+ apps_for_job_t data = {
2416+ .jobname = jobname,
2417+ .apps = apps,
2418+ .truncate_legacy = truncate_legacy
2419+ };
2420+
2421+ foreach_job_instance(con, jobname, apps_for_job_instance, &data);
2422 }
2423
2424 gchar **
2425 upstart_app_launch_list_running_apps (void)
2426 {
2427- NihDBusProxy * proxy = NULL;
2428-
2429- proxy = nih_proxy_create();
2430- if (proxy == NULL) {
2431- return g_new0(gchar *, 1);
2432- }
2433+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2434+ g_return_val_if_fail(con != NULL, g_new0(gchar *, 1));
2435
2436 GArray * apps = g_array_new(TRUE, TRUE, sizeof(gchar *));
2437
2438- apps_for_job(proxy, "application-legacy", apps, TRUE);
2439- apps_for_job(proxy, "application-click", apps, FALSE);
2440+ apps_for_job(con, "application-legacy", apps, TRUE);
2441+ apps_for_job(con, "application-click", apps, FALSE);
2442
2443- nih_unref(proxy, NULL);
2444+ g_object_unref(con);
2445
2446 return (gchar **)g_array_free(apps, FALSE);
2447 }
2448
2449+typedef struct {
2450+ GPid pid;
2451+ const gchar * appid;
2452+ const gchar * jobname;
2453+} pid_for_job_t;
2454+
2455+static void
2456+pid_for_job_instance (GDBusConnection * con, GVariant * props_dict, gpointer user_data)
2457+{
2458+ GVariant * namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
2459+ if (namev == NULL) {
2460+ return;
2461+ }
2462+
2463+ pid_for_job_t * data = (pid_for_job_t *)user_data;
2464+ gchar * instance_name = g_variant_dup_string(namev, NULL);
2465+ g_variant_unref(namev);
2466+
2467+ if (g_strcmp0(data->jobname, "application-legacy") == 0) {
2468+ gchar * last_dash = g_strrstr(instance_name, "-");
2469+ if (last_dash != NULL) {
2470+ last_dash[0] = '\0';
2471+ }
2472+ }
2473+
2474+ if (g_strcmp0(instance_name, data->appid) == 0) {
2475+ GVariant * processv = g_variant_lookup_value(props_dict, "processes", G_VARIANT_TYPE("a(si)"));
2476+
2477+ if (processv != NULL) {
2478+ if (g_variant_n_children(processv) > 0) {
2479+ GVariant * first_entry = g_variant_get_child_value(processv, 0);
2480+ GVariant * pidv = g_variant_get_child_value(first_entry, 1);
2481+
2482+ data->pid = g_variant_get_int32(pidv);
2483+
2484+ g_variant_unref(pidv);
2485+ g_variant_unref(first_entry);
2486+ }
2487+
2488+ g_variant_unref(processv);
2489+ }
2490+ }
2491+
2492+ g_free(instance_name);
2493+}
2494+
2495 /* Look for the app for a job */
2496 static GPid
2497-pid_for_job (NihDBusProxy * upstart, const gchar * job, const gchar * appid)
2498+pid_for_job (GDBusConnection * con, const gchar * jobname, const gchar * appid)
2499 {
2500- nih_local char * job_path = NULL;
2501- if (upstart_get_job_by_name_sync(NULL, upstart, job, &job_path) != 0) {
2502- g_warning("Unable to find job '%s'", job);
2503- return 0;
2504- }
2505-
2506- NihDBusProxy * job_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
2507- upstart->name,
2508- job_path,
2509- NULL, NULL);
2510-
2511- if (job_proxy == NULL) {
2512- g_warning("Unable to build proxy to Job '%s'", job);
2513- return 0;
2514- }
2515-
2516- nih_local char ** instances;
2517- if (job_class_get_all_instances_sync(NULL, job_proxy, &instances) != 0) {
2518- g_warning("Unable to get instances for job '%s'", job);
2519- nih_unref(job_proxy, NULL);
2520- return 0;
2521- }
2522-
2523- GPid pid = 0;
2524- int jobnum;
2525- for (jobnum = 0; instances[jobnum] != NULL && pid == 0; jobnum++) {
2526- NihDBusProxy * instance_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
2527- upstart->name,
2528- instances[jobnum],
2529- NULL, NULL);
2530-
2531- nih_local char * instance_name = NULL;
2532- if (job_get_name_sync(NULL, instance_proxy, &instance_name) == 0) {
2533- if (g_strcmp0(job, "application-legacy") == 0) {
2534- gchar * last_dash = g_strrstr(instance_name, "-");
2535- if (last_dash != NULL) {
2536- last_dash[0] = '\0';
2537- }
2538- }
2539- } else {
2540- g_warning("Unable to get name for instance '%s' of job '%s'", instances[jobnum], job);
2541- }
2542-
2543- if (g_strcmp0(instance_name, appid) == 0) {
2544- nih_local JobProcessesElement ** elements;
2545- if (job_get_processes_sync(NULL, instance_proxy, &elements) == 0) {
2546- pid = elements[0]->item1;
2547- }
2548- }
2549-
2550- nih_unref(instance_proxy, NULL);
2551- }
2552-
2553- nih_unref(job_proxy, NULL);
2554-
2555- return pid;
2556+ pid_for_job_t data = {
2557+ .jobname = jobname,
2558+ .appid = appid,
2559+ .pid = 0
2560+ };
2561+
2562+ foreach_job_instance(con, jobname, pid_for_job_instance, &data);
2563+
2564+ return data.pid;
2565 }
2566
2567 GPid
2568 upstart_app_launch_get_primary_pid (const gchar * appid)
2569 {
2570- NihDBusProxy * proxy = NULL;
2571+ g_return_val_if_fail(appid != NULL, 0);
2572
2573- proxy = nih_proxy_create();
2574- if (proxy == NULL) {
2575- return 0;
2576- }
2577+ GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
2578+ g_return_val_if_fail(con != NULL, 0);
2579
2580 GPid pid = 0;
2581
2582 if (pid == 0) {
2583- pid = pid_for_job(proxy, "application-legacy", appid);
2584+ pid = pid_for_job(con, "application-legacy", appid);
2585 }
2586
2587 if (pid == 0) {
2588- pid = pid_for_job(proxy, "application-click", appid);
2589+ pid = pid_for_job(con, "application-click", appid);
2590 }
2591
2592- nih_unref(proxy, NULL);
2593+ g_object_unref(con);
2594
2595 return pid;
2596 }
2597@@ -688,6 +977,8 @@
2598 gboolean
2599 upstart_app_launch_pid_in_app_id (GPid pid, const gchar * appid)
2600 {
2601+ g_return_val_if_fail(appid != NULL, FALSE);
2602+
2603 if (pid == 0) {
2604 return FALSE;
2605 }
2606
2607=== modified file 'libupstart-app-launch/upstart-app-launch.h'
2608--- libupstart-app-launch/upstart-app-launch.h 2014-01-29 02:33:52 +0000
2609+++ libupstart-app-launch/upstart-app-launch.h 2014-02-11 03:28:22 +0000
2610@@ -29,35 +29,41 @@
2611 #endif
2612
2613 /**
2614- * upstart_app_launch_app_failed_t:
2615+ * UpstartAppLaunchAppFailed:
2616 *
2617 * Types of failure that we report.
2618 */
2619-enum _upstart_app_launch_app_failed_t {
2620- UPSTART_APP_LAUNCH_APP_FAILED_CRASH,
2621- UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE,
2622-};
2623-typedef enum _upstart_app_launch_app_failed_t upstart_app_launch_app_failed_t;
2624+typedef enum { /*< prefix=UPSTART_APP_LAUNCH_APP_FAILED */
2625+ UPSTART_APP_LAUNCH_APP_FAILED_CRASH, /*< nick=crash */
2626+ UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE, /*< nick=start-failure */
2627+} UpstartAppLaunchAppFailed;
2628+typedef UpstartAppLaunchAppFailed upstart_app_launch_app_failed_t;
2629
2630 /**
2631- * upstart_app_launch_app_observer_t:
2632+ * UpstartAppLaunchAppObserver:
2633 *
2634 * Function prototype for application observers.
2635 */
2636-typedef void (*upstart_app_launch_app_observer_t) (const gchar * appid, gpointer user_data);
2637+typedef void (*UpstartAppLaunchAppObserver) (const gchar * appid, gpointer user_data);
2638+
2639+/* Backwards compatible. Drop when making API bump. */
2640+typedef UpstartAppLaunchAppObserver upstart_app_launch_app_observer_t;
2641
2642 /**
2643- * upstart_app_launch_app_failed_observer_t:
2644+ * UpstartAppLaunchAppFailedObserver:
2645 *
2646 * Function prototype for application failed observers.
2647 */
2648-typedef void (*upstart_app_launch_app_failed_observer_t) (const gchar * appid, upstart_app_launch_app_failed_t failure_type, gpointer user_data);
2649+typedef void (*UpstartAppLaunchAppFailedObserver) (const gchar * appid, UpstartAppLaunchAppFailed failure_type, gpointer user_data);
2650+
2651+/* Backwards compatible. Drop when making API bump. */
2652+typedef UpstartAppLaunchAppFailedObserver upstart_app_launch_app_failed_observer_t;
2653
2654
2655 /**
2656 * upstart_app_launch_start_application:
2657 * @appid: ID of the application to launch
2658- * @uris: (allow none): A NULL terminated list of URIs to send to the application
2659+ * @uris: (allow-none) (array zero-terminated=1) (element-type utf8) (transfer none): A NULL terminated list of URIs to send to the application
2660 *
2661 * Asks upstart to launch an application.
2662 *
2663@@ -81,8 +87,8 @@
2664
2665 /**
2666 * upstart_app_launch_observer_add_app_starting:
2667- * @observer: Callback when an application is about to start
2668- * @user_data: (allow none): Data to pass to the observer
2669+ * @observer: (scope notified): Callback when an application is about to start
2670+ * @user_data: (closure) (allow-none): Data to pass to the observer
2671 *
2672 * Sets up a callback to get called each time an application
2673 * is about to start. The application will not start until the
2674@@ -90,50 +96,50 @@
2675 *
2676 * Return value: Whether adding the observer was successful.
2677 */
2678-gboolean upstart_app_launch_observer_add_app_starting (upstart_app_launch_app_observer_t observer,
2679+gboolean upstart_app_launch_observer_add_app_starting (UpstartAppLaunchAppObserver observer,
2680 gpointer user_data);
2681 /**
2682 * upstart_app_launch_observer_add_app_started:
2683- * @observer: Callback when an application started
2684- * @user_data: (allow none): Data to pass to the observer
2685+ * @observer: (scope notified): Callback when an application started
2686+ * @user_data: (closure) (allow-none): Data to pass to the observer
2687 *
2688 * Sets up a callback to get called each time an application
2689 * has been started.
2690 *
2691 * Return value: Whether adding the observer was successful.
2692 */
2693-gboolean upstart_app_launch_observer_add_app_started (upstart_app_launch_app_observer_t observer,
2694+gboolean upstart_app_launch_observer_add_app_started (UpstartAppLaunchAppObserver observer,
2695 gpointer user_data);
2696 /**
2697 * upstart_app_launch_observer_add_app_stop:
2698- * @observer: Callback when an application stops
2699- * @user_data: (allow none): Data to pass to the observer
2700+ * @observer: (scope notified): Callback when an application stops
2701+ * @user_data: (closure) (allow-none): Data to pass to the observer
2702 *
2703 * Sets up a callback to get called each time an application
2704 * stops.
2705 *
2706 * Return value: Whether adding the observer was successful.
2707 */
2708-gboolean upstart_app_launch_observer_add_app_stop (upstart_app_launch_app_observer_t observer,
2709+gboolean upstart_app_launch_observer_add_app_stop (UpstartAppLaunchAppObserver observer,
2710 gpointer user_data);
2711
2712 /**
2713 * upstart_app_launch_observer_add_app_focus:
2714- * @observer: Callback when an application is started for the second time
2715- * @user_data: (allow none): Data to pass to the observer
2716+ * @observer: (scope notified): Callback when an application is started for the second time
2717+ * @user_data: (closure) (allow-none): Data to pass to the observer
2718 *
2719 * Sets up a callback to get called each time an app gets called
2720 * that is already running, so we request it to be focused again.
2721 *
2722 * Return value: Whether adding the observer was successful.
2723 */
2724-gboolean upstart_app_launch_observer_add_app_focus (upstart_app_launch_app_observer_t observer,
2725+gboolean upstart_app_launch_observer_add_app_focus (UpstartAppLaunchAppObserver observer,
2726 gpointer user_data);
2727
2728 /**
2729 * upstart_app_launch_observer_add_app_resume:
2730- * @observer: Callback when an application is started and possibly asleep
2731- * @user_data: (allow none): Data to pass to the observer
2732+ * @observer: (scope notified): Callback when an application is started and possibly asleep
2733+ * @user_data: (closure) (allow-none): Data to pass to the observer
2734 *
2735 * Sets up a callback to get called each time an app gets called
2736 * that is already running, so we request it to be given CPU time.
2737@@ -141,96 +147,96 @@
2738 *
2739 * Return value: Whether adding the observer was successful.
2740 */
2741-gboolean upstart_app_launch_observer_add_app_resume (upstart_app_launch_app_observer_t observer,
2742+gboolean upstart_app_launch_observer_add_app_resume (UpstartAppLaunchAppObserver observer,
2743 gpointer user_data);
2744
2745 /**
2746 * upstart_app_launch_observer_add_app_failed:
2747- * @observer: Callback when an application fails
2748- * @user_data: (allow none): Data to pass to the observer
2749+ * @observer: (scope notified): Callback when an application fails
2750+ * @user_data: (allow-none) (closure): Data to pass to the observer
2751 *
2752 * Sets up a callback to get called each time an application
2753 * stops via failure.
2754 *
2755 * Return value: Whether adding the observer was successful.
2756 */
2757-gboolean upstart_app_launch_observer_add_app_failed (upstart_app_launch_app_failed_observer_t observer,
2758- gpointer user_data);
2759+gboolean upstart_app_launch_observer_add_app_failed (UpstartAppLaunchAppFailedObserver observer,
2760+ gpointer user_data);
2761
2762 /**
2763 * upstart_app_launch_observer_delete_app_starting:
2764- * @observer: Callback to remove
2765- * @user_data: (allow none): Data that was passed to the observer
2766+ * @observer: (scope notified): Callback to remove
2767+ * @user_data: (closure) (allow-none): Data that was passed to the observer
2768 *
2769 * Removes a previously registered callback to ensure it no longer
2770 * gets signaled.
2771 *
2772 * Return value: Whether deleting the observer was successful.
2773 */
2774-gboolean upstart_app_launch_observer_delete_app_starting (upstart_app_launch_app_observer_t observer,
2775+gboolean upstart_app_launch_observer_delete_app_starting (UpstartAppLaunchAppObserver observer,
2776 gpointer user_data);
2777 /**
2778 * upstart_app_launch_observer_delete_app_started:
2779- * @observer: Callback to remove
2780- * @user_data: (allow none): Data that was passed to the observer
2781+ * @observer: (scope notified): Callback to remove
2782+ * @user_data: (closure) (allow-none): Data that was passed to the observer
2783 *
2784 * Removes a previously registered callback to ensure it no longer
2785 * gets signaled.
2786 *
2787 * Return value: Whether deleting the observer was successful.
2788 */
2789-gboolean upstart_app_launch_observer_delete_app_started (upstart_app_launch_app_observer_t observer,
2790+gboolean upstart_app_launch_observer_delete_app_started (UpstartAppLaunchAppObserver observer,
2791 gpointer user_data);
2792 /**
2793 * upstart_app_launch_observer_delete_app_stop:
2794- * @observer: Callback to remove
2795- * @user_data: (allow none): Data that was passed to the observer
2796+ * @observer: (scope notified): Callback to remove
2797+ * @user_data: (closure) (allow-none): Data that was passed to the observer
2798 *
2799 * Removes a previously registered callback to ensure it no longer
2800 * gets signaled.
2801 *
2802 * Return value: Whether deleting the observer was successful.
2803 */
2804-gboolean upstart_app_launch_observer_delete_app_stop (upstart_app_launch_app_observer_t observer,
2805+gboolean upstart_app_launch_observer_delete_app_stop (UpstartAppLaunchAppObserver observer,
2806 gpointer user_data);
2807
2808 /**
2809 * upstart_app_launch_observer_delete_app_focus:
2810- * @observer: Callback to remove
2811- * @user_data: (allow none): Data that was passed to the observer
2812+ * @observer: (scope notified): Callback to remove
2813+ * @user_data: (closure) (allow-none): Data that was passed to the observer
2814 *
2815 * Removes a previously registered callback to ensure it no longer
2816 * gets signaled.
2817 *
2818 * Return value: Whether deleting the observer was successful.
2819 */
2820-gboolean upstart_app_launch_observer_delete_app_focus (upstart_app_launch_app_observer_t observer,
2821+gboolean upstart_app_launch_observer_delete_app_focus (UpstartAppLaunchAppObserver observer,
2822 gpointer user_data);
2823
2824 /**
2825 * upstart_app_launch_observer_delete_app_resume:
2826- * @observer: Callback to remove
2827- * @user_data: (allow none): Data that was passed to the observer
2828+ * @observer: (scope notified): Callback to remove
2829+ * @user_data: (closure) (allow-none): Data that was passed to the observer
2830 *
2831 * Removes a previously registered callback to ensure it no longer
2832 * gets signaled.
2833 *
2834 * Return value: Whether deleting the observer was successful.
2835 */
2836-gboolean upstart_app_launch_observer_delete_app_resume (upstart_app_launch_app_observer_t observer,
2837+gboolean upstart_app_launch_observer_delete_app_resume (UpstartAppLaunchAppObserver observer,
2838 gpointer user_data);
2839
2840 /**
2841 * upstart_app_launch_observer_delete_app_failed:
2842- * @observer: Callback to remove
2843- * @user_data: (allow none): Data to pass to the observer
2844+ * @observer: (scope notified): Callback to remove
2845+ * @user_data: (closure) (allow-none): Data to pass to the observer
2846 *
2847 * Removes a previously registered callback to ensure it no longer
2848 * gets signaled.
2849 *
2850 * Return value: Whether deleting the observer was successful.
2851 */
2852-gboolean upstart_app_launch_observer_delete_app_failed (upstart_app_launch_app_failed_observer_t observer,
2853+gboolean upstart_app_launch_observer_delete_app_failed (UpstartAppLaunchAppFailedObserver observer,
2854 gpointer user_data);
2855 /**
2856 * upstart_app_launch_list_running_apps:
2857
2858=== removed file 'second-exec-trace.tp'
2859--- second-exec-trace.tp 2013-12-04 17:32:23 +0000
2860+++ second-exec-trace.tp 1970-01-01 00:00:00 +0000
2861@@ -1,16 +0,0 @@
2862-
2863-TRACEPOINT_EVENT(upstart_app_launch, second_exec_start, TP_ARGS(0), TP_FIELDS())
2864-TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_resume, TP_ARGS(0), TP_FIELDS())
2865-TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_complete, TP_ARGS(0), TP_FIELDS())
2866-TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_timeout, TP_ARGS(0), TP_FIELDS())
2867-TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_focus, TP_ARGS(0), TP_FIELDS())
2868-TRACEPOINT_EVENT(upstart_app_launch, second_exec_finish, TP_ARGS(0), TP_FIELDS())
2869-TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_dbus_names, TP_ARGS(0), TP_FIELDS())
2870-TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_primary_pid, TP_ARGS(0), TP_FIELDS())
2871-TRACEPOINT_EVENT(upstart_app_launch, second_exec_request_pid, TP_ARGS(0), TP_FIELDS())
2872-TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_pid, TP_ARGS(0), TP_FIELDS())
2873-TRACEPOINT_EVENT(upstart_app_launch, second_exec_contact_app, TP_ARGS(0), TP_FIELDS())
2874-TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_contacted, TP_ARGS(0), TP_FIELDS())
2875-TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_error, TP_ARGS(0), TP_FIELDS())
2876-TRACEPOINT_EVENT(upstart_app_launch, second_exec_connection_complete, TP_ARGS(0), TP_FIELDS())
2877-
2878
2879=== removed file 'second-exec.c'
2880--- second-exec.c 2013-12-05 17:08:13 +0000
2881+++ second-exec.c 1970-01-01 00:00:00 +0000
2882@@ -1,40 +0,0 @@
2883-/*
2884- * Copyright 2013 Canonical Ltd.
2885- *
2886- * This program is free software: you can redistribute it and/or modify it
2887- * under the terms of the GNU General Public License version 3, as published
2888- * by the Free Software Foundation.
2889- *
2890- * This program is distributed in the hope that it will be useful, but
2891- * WITHOUT ANY WARRANTY; without even the implied warranties of
2892- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2893- * PURPOSE. See the GNU General Public License for more details.
2894- *
2895- * You should have received a copy of the GNU General Public License along
2896- * with this program. If not, see <http://www.gnu.org/licenses/>.
2897- *
2898- * Authors:
2899- * Ted Gould <ted.gould@canonical.com>
2900- */
2901-
2902-#include "second-exec-core.h"
2903-
2904-int
2905-main (int argc, char * argv[])
2906-{
2907- if (argc != 1) {
2908- g_error("Should be called as: %s", argv[0]);
2909- return 1;
2910- }
2911-
2912- const gchar * appid = g_getenv("APP_ID");
2913- const gchar * appuris = g_getenv("APP_URIS");
2914-
2915- g_setenv("LTTNG_UST_REGISTER_TIMEOUT", "0", FALSE); /* Set to zero if not set */
2916-
2917- if (second_exec(appid, appuris)) {
2918- return 0;
2919- } else {
2920- return 1;
2921- }
2922-}
2923
2924=== modified file 'tests/CMakeLists.txt'
2925--- tests/CMakeLists.txt 2014-01-13 15:16:24 +0000
2926+++ tests/CMakeLists.txt 2014-02-11 03:28:22 +0000
2927@@ -25,16 +25,6 @@
2928
2929 add_test (helper-handshake-test helper-handshake-test)
2930
2931-# Second Exec Test
2932-
2933-include_directories("${CMAKE_SOURCE_DIR}/libupstart-app-launch")
2934-
2935-add_executable (second-exec-test
2936- second-exec-test.cc
2937- upstart-app-launch-mock.c)
2938-target_link_libraries (second-exec-test helpers gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} upstart-launcher second-exec-core)
2939-add_test (second-exec-test second-exec-test)
2940-
2941 # libUAL Test
2942
2943 include_directories("${CMAKE_SOURCE_DIR}/libupstart-app-launch")
2944@@ -43,14 +33,16 @@
2945 libual-test.cc)
2946 target_link_libraries (libual-test helpers gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} upstart-launcher)
2947
2948-# NOTE: Tests are broken into individual runs to avoid problems with libdbus
2949-add_test (NAME libual-test-start COMMAND libual-test --gtest_filter=*StartApplication)
2950-add_test (NAME libual-test-stop COMMAND libual-test --gtest_filter=*StopApplication)
2951-add_test (NAME libual-test-pid COMMAND libual-test --gtest_filter=*ApplicationPid)
2952-add_test (NAME libual-test-app-id COMMAND libual-test --gtest_filter=*ApplicationId)
2953-add_test (NAME libual-test-list COMMAND libual-test --gtest_filter=*ApplicationList)
2954-add_test (NAME libual-test-observer COMMAND libual-test --gtest_filter=*StartStopObserver)
2955-add_test (NAME libual-test-starting COMMAND libual-test --gtest_filter=*StartingResponses)
2956+add_test (NAME libual-test COMMAND libual-test)
2957+
2958+# Failure Test
2959+
2960+add_definitions ( -DAPP_FAILED_TOOL="${CMAKE_BINARY_DIR}/application-failed" )
2961+
2962+add_executable (failure-test
2963+ failure-test.cc)
2964+target_link_libraries (failure-test gtest ${GTEST_LIBS} upstart-launcher)
2965+add_test (failure-test failure-test)
2966
2967 # ZG Test
2968
2969
2970=== added file 'tests/applications/multiple.desktop'
2971--- tests/applications/multiple.desktop 1970-01-01 00:00:00 +0000
2972+++ tests/applications/multiple.desktop 2014-02-11 03:28:22 +0000
2973@@ -0,0 +1,8 @@
2974+[Desktop Entry]
2975+Name=Multiple
2976+Type=Application
2977+Exec=multiple
2978+NoDisplay=false
2979+Hidden=false
2980+Terminal=false
2981+X-Ubuntu-Single-Instance=false
2982
2983=== added file 'tests/applications/single.desktop'
2984--- tests/applications/single.desktop 1970-01-01 00:00:00 +0000
2985+++ tests/applications/single.desktop 2014-02-11 03:28:22 +0000
2986@@ -0,0 +1,8 @@
2987+[Desktop Entry]
2988+Name=Single
2989+Type=Application
2990+Exec=single
2991+NoDisplay=false
2992+Hidden=false
2993+Terminal=false
2994+X-Ubuntu-Single-Instance=true
2995
2996=== added file 'tests/failure-test.cc'
2997--- tests/failure-test.cc 1970-01-01 00:00:00 +0000
2998+++ tests/failure-test.cc 2014-02-11 03:28:22 +0000
2999@@ -0,0 +1,151 @@
3000+/*
3001+ * Copyright 2013 Canonical Ltd.
3002+ *
3003+ * This program is free software: you can redistribute it and/or modify it
3004+ * under the terms of the GNU General Public License version 3, as published
3005+ * by the Free Software Foundation.
3006+ *
3007+ * This program is distributed in the hope that it will be useful, but
3008+ * WITHOUT ANY WARRANTY; without even the implied warranties of
3009+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3010+ * PURPOSE. See the GNU General Public License for more details.
3011+ *
3012+ * You should have received a copy of the GNU General Public License along
3013+ * with this program. If not, see <http://www.gnu.org/licenses/>.
3014+ *
3015+ * Authors:
3016+ * Ted Gould <ted.gould@canonical.com>
3017+ */
3018+
3019+#include <gtest/gtest.h>
3020+#include <glib/gstdio.h>
3021+#include <gio/gio.h>
3022+#include <upstart-app-launch.h>
3023+
3024+class FailureTest : public ::testing::Test
3025+{
3026+ private:
3027+ GTestDBus * testbus = NULL;
3028+
3029+ protected:
3030+ virtual void SetUp() {
3031+ testbus = g_test_dbus_new(G_TEST_DBUS_NONE);
3032+ g_test_dbus_up(testbus);
3033+ }
3034+
3035+ virtual void TearDown() {
3036+ g_test_dbus_down(testbus);
3037+ g_clear_object(&testbus);
3038+ return;
3039+ }
3040+
3041+ static gboolean pause_helper (gpointer pmainloop) {
3042+ g_main_loop_quit(static_cast<GMainLoop *>(pmainloop));
3043+ return G_SOURCE_REMOVE;
3044+ }
3045+
3046+ void pause (guint time) {
3047+ if (time > 0) {
3048+ GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
3049+ g_timeout_add(time, pause_helper, mainloop);
3050+
3051+ g_main_loop_run(mainloop);
3052+
3053+ g_main_loop_unref(mainloop);
3054+ }
3055+
3056+ while (g_main_pending()) {
3057+ g_main_iteration(TRUE);
3058+ }
3059+ }
3060+};
3061+
3062+static void
3063+failed_observer (const gchar * appid, upstart_app_launch_app_failed_t reason, gpointer user_data)
3064+{
3065+ if (reason == UPSTART_APP_LAUNCH_APP_FAILED_CRASH) {
3066+ std::string * last = static_cast<std::string *>(user_data);
3067+ *last = appid;
3068+ }
3069+ return;
3070+}
3071+
3072+TEST_F(FailureTest, CrashTest)
3073+{
3074+ g_setenv("EXIT_STATUS", "-100", TRUE);
3075+ g_setenv("JOB", "application-click", TRUE);
3076+ g_setenv("INSTANCE", "foo", TRUE);
3077+
3078+ std::string last_observer;
3079+ ASSERT_TRUE(upstart_app_launch_observer_add_app_failed(failed_observer, &last_observer));
3080+
3081+ /* Status based */
3082+ ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
3083+ pause(100);
3084+
3085+ EXPECT_EQ("foo", last_observer);
3086+
3087+ last_observer.clear();
3088+ g_unsetenv("EXIT_STATUS");
3089+ g_setenv("EXIT_SIGNAL", "KILL", TRUE);
3090+
3091+ /* Signal based */
3092+ ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
3093+ pause(100);
3094+
3095+ EXPECT_EQ("foo", last_observer);
3096+
3097+ ASSERT_TRUE(upstart_app_launch_observer_delete_app_failed(failed_observer, &last_observer));
3098+
3099+ return;
3100+}
3101+
3102+TEST_F(FailureTest, LegacyTest)
3103+{
3104+ g_setenv("EXIT_STATUS", "-100", TRUE);
3105+ g_setenv("JOB", "application-legacy", TRUE);
3106+ g_setenv("INSTANCE", "foo-1234", TRUE);
3107+
3108+ std::string last_observer;
3109+ ASSERT_TRUE(upstart_app_launch_observer_add_app_failed(failed_observer, &last_observer));
3110+
3111+ /* Status based */
3112+ ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
3113+ pause(100);
3114+
3115+ EXPECT_EQ("foo", last_observer);
3116+
3117+ ASSERT_TRUE(upstart_app_launch_observer_delete_app_failed(failed_observer, &last_observer));
3118+
3119+ return;
3120+}
3121+
3122+static void
3123+failed_start_observer (const gchar * appid, upstart_app_launch_app_failed_t reason, gpointer user_data)
3124+{
3125+ if (reason == UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE) {
3126+ std::string * last = static_cast<std::string *>(user_data);
3127+ *last = appid;
3128+ }
3129+ return;
3130+}
3131+
3132+TEST_F(FailureTest, StartTest)
3133+{
3134+ g_setenv("JOB", "application-click", TRUE);
3135+ g_setenv("INSTANCE", "foo", TRUE);
3136+ g_unsetenv("EXIT_STATUS");
3137+ g_unsetenv("EXIT_SIGNAL");
3138+
3139+ std::string last_observer;
3140+ ASSERT_TRUE(upstart_app_launch_observer_add_app_failed(failed_start_observer, &last_observer));
3141+
3142+ ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
3143+ pause(100);
3144+
3145+ EXPECT_EQ("foo", last_observer);
3146+
3147+ ASSERT_TRUE(upstart_app_launch_observer_delete_app_failed(failed_start_observer, &last_observer));
3148+
3149+ return;
3150+}
3151
3152=== modified file 'tests/libual-test.cc'
3153--- tests/libual-test.cc 2014-01-29 02:24:06 +0000
3154+++ tests/libual-test.cc 2014-02-11 03:28:22 +0000
3155@@ -31,6 +31,26 @@
3156 DbusTestService * service = NULL;
3157 DbusTestDbusMock * mock = NULL;
3158 GDBusConnection * bus = NULL;
3159+ std::string last_focus_appid;
3160+ std::string last_resume_appid;
3161+ guint resume_timeout = 0;
3162+
3163+ private:
3164+ static void focus_cb (const gchar * appid, gpointer user_data) {
3165+ g_debug("Focus Callback: %s", appid);
3166+ LibUAL * _this = static_cast<LibUAL *>(user_data);
3167+ _this->last_focus_appid = appid;
3168+ }
3169+
3170+ static void resume_cb (const gchar * appid, gpointer user_data) {
3171+ g_debug("Resume Callback: %s", appid);
3172+ LibUAL * _this = static_cast<LibUAL *>(user_data);
3173+ _this->last_resume_appid = appid;
3174+
3175+ if (_this->resume_timeout > 0) {
3176+ _this->pause(_this->resume_timeout);
3177+ }
3178+ }
3179
3180 protected:
3181 /* Useful debugging stuff, but not on by default. You really want to
3182@@ -48,6 +68,12 @@
3183 }
3184
3185 virtual void SetUp() {
3186+ gchar * linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL);
3187+ g_setenv("UPSTART_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE);
3188+ g_free(linkfarmpath);
3189+
3190+ g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
3191+
3192 service = dbus_test_service_new(NULL);
3193 g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
3194 const gchar * oldpath = g_getenv("PATH");
3195@@ -81,6 +107,14 @@
3196 DbusTestDbusMockObject * jobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
3197
3198 dbus_test_dbus_mock_object_add_method(mock, jobobj,
3199+ "Start",
3200+ G_VARIANT_TYPE("(asb)"),
3201+ NULL,
3202+ "if args[0][0] == 'APP_ID=foo':"
3203+ " raise dbus.exceptions.DBusException('Foo running', name='com.ubuntu.Upstart0_6.Error.AlreadyStarted')",
3204+ NULL);
3205+
3206+ dbus_test_dbus_mock_object_add_method(mock, jobobj,
3207 "Stop",
3208 G_VARIANT_TYPE("(asb)"),
3209 NULL,
3210@@ -100,15 +134,24 @@
3211 G_VARIANT_TYPE_STRING,
3212 g_variant_new_string("foo"),
3213 NULL);
3214+ gchar * process_var = g_strdup_printf("[('main', %d)]", getpid());
3215 dbus_test_dbus_mock_object_add_property(mock, instobj,
3216 "processes",
3217 G_VARIANT_TYPE("a(si)"),
3218- g_variant_new_parsed("[('main', 1234)]"),
3219+ g_variant_new_parsed(process_var),
3220 NULL);
3221+ g_free(process_var);
3222
3223 DbusTestDbusMockObject * ljobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
3224
3225 dbus_test_dbus_mock_object_add_method(mock, ljobobj,
3226+ "Start",
3227+ G_VARIANT_TYPE("(asb)"),
3228+ NULL,
3229+ "",
3230+ NULL);
3231+
3232+ dbus_test_dbus_mock_object_add_method(mock, ljobobj,
3233 "Stop",
3234 G_VARIANT_TYPE("(asb)"),
3235 NULL,
3236@@ -140,9 +183,15 @@
3237 bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3238 g_dbus_connection_set_exit_on_close(bus, FALSE);
3239 g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);
3240+
3241+ ASSERT_TRUE(upstart_app_launch_observer_add_app_focus(focus_cb, this));
3242+ ASSERT_TRUE(upstart_app_launch_observer_add_app_resume(resume_cb, this));
3243 }
3244
3245 virtual void TearDown() {
3246+ upstart_app_launch_observer_delete_app_focus(focus_cb, this);
3247+ upstart_app_launch_observer_delete_app_resume(resume_cb, this);
3248+
3249 g_clear_object(&mock);
3250 g_clear_object(&service);
3251
3252@@ -150,12 +199,10 @@
3253
3254 unsigned int cleartry = 0;
3255 while (bus != NULL && cleartry < 100) {
3256- g_usleep(100000);
3257- while (g_main_pending()) {
3258- g_main_iteration(TRUE);
3259- }
3260+ pause(100);
3261 cleartry++;
3262 }
3263+ ASSERT_EQ(bus, nullptr);
3264 }
3265
3266 bool check_env (GVariant * env_array, const gchar * var, const gchar * value) {
3267@@ -189,18 +236,17 @@
3268 }
3269
3270 static gboolean pause_helper (gpointer pmainloop) {
3271- g_main_loop_quit((GMainLoop *)pmainloop);
3272+ g_main_loop_quit(static_cast<GMainLoop *>(pmainloop));
3273 return G_SOURCE_REMOVE;
3274 }
3275
3276 void pause (guint time) {
3277 if (time > 0) {
3278 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
3279- guint timer = g_timeout_add(time, pause_helper, mainloop);
3280+ g_timeout_add(time, pause_helper, mainloop);
3281
3282 g_main_loop_run(mainloop);
3283
3284- g_source_remove(timer);
3285 g_main_loop_unref(mainloop);
3286 }
3287
3288@@ -212,35 +258,31 @@
3289
3290 TEST_F(LibUAL, StartApplication)
3291 {
3292- DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
3293+ DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
3294
3295 /* Basic make sure we can send the event */
3296- ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
3297- ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "EmitEvent", NULL, NULL), 1);
3298+ ASSERT_TRUE(upstart_app_launch_start_application("foolike", NULL));
3299+ EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
3300
3301 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
3302
3303 /* Now look at the details of the call */
3304- ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
3305+ ASSERT_TRUE(upstart_app_launch_start_application("foolike", NULL));
3306
3307 guint len = 0;
3308- const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "EmitEvent", &len, NULL);
3309- ASSERT_NE(calls, nullptr);
3310- ASSERT_EQ(len, 1);
3311-
3312- ASSERT_STREQ(calls->name, "EmitEvent");
3313- ASSERT_EQ(g_variant_n_children(calls->params), 3);
3314-
3315- GVariant * name = g_variant_get_child_value(calls->params, 0);
3316- ASSERT_STREQ(g_variant_get_string(name, NULL), "application-start");
3317- g_variant_unref(name);
3318-
3319- GVariant * block = g_variant_get_child_value(calls->params, 2);
3320- ASSERT_FALSE(g_variant_get_boolean(block));
3321+ const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
3322+ EXPECT_NE(nullptr, calls);
3323+ EXPECT_EQ(1, len);
3324+
3325+ EXPECT_STREQ("Start", calls->name);
3326+ EXPECT_EQ(2, g_variant_n_children(calls->params));
3327+
3328+ GVariant * block = g_variant_get_child_value(calls->params, 1);
3329+ EXPECT_TRUE(g_variant_get_boolean(block));
3330 g_variant_unref(block);
3331
3332- GVariant * env = g_variant_get_child_value(calls->params, 1);
3333- ASSERT_TRUE(check_env(env, "APP_ID", "foo"));
3334+ GVariant * env = g_variant_get_child_value(calls->params, 0);
3335+ EXPECT_TRUE(check_env(env, "APP_ID", "foolike"));
3336 g_variant_unref(env);
3337
3338 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
3339@@ -252,16 +294,16 @@
3340 "file:///home/phablet/test.txt",
3341 NULL
3342 };
3343- ASSERT_TRUE(upstart_app_launch_start_application("foo", urls));
3344+ ASSERT_TRUE(upstart_app_launch_start_application("foolike", urls));
3345
3346 len = 0;
3347- calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "EmitEvent", &len, NULL);
3348- ASSERT_NE(calls, nullptr);
3349- ASSERT_EQ(len, 1);
3350+ calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
3351+ EXPECT_NE(nullptr, calls);
3352+ EXPECT_EQ(1, len);
3353
3354- env = g_variant_get_child_value(calls->params, 1);
3355- ASSERT_TRUE(check_env(env, "APP_ID", "foo"));
3356- ASSERT_TRUE(check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
3357+ env = g_variant_get_child_value(calls->params, 0);
3358+ EXPECT_TRUE(check_env(env, "APP_ID", "foolike"));
3359+ EXPECT_TRUE(check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
3360 g_variant_unref(env);
3361
3362 return;
3363@@ -279,10 +321,10 @@
3364
3365 TEST_F(LibUAL, ApplicationPid)
3366 {
3367- ASSERT_EQ(upstart_app_launch_get_primary_pid("foo"), 1234);
3368- ASSERT_EQ(upstart_app_launch_get_primary_pid("bar"), 5678);
3369- ASSERT_TRUE(upstart_app_launch_pid_in_app_id(1234, "foo"));
3370- ASSERT_FALSE(upstart_app_launch_pid_in_app_id(5678, "foo"));
3371+ EXPECT_EQ(upstart_app_launch_get_primary_pid("foo"), getpid());
3372+ EXPECT_EQ(upstart_app_launch_get_primary_pid("bar"), 5678);
3373+ EXPECT_TRUE(upstart_app_launch_pid_in_app_id(getpid(), "foo"));
3374+ EXPECT_FALSE(upstart_app_launch_pid_in_app_id(5678, "foo"));
3375 }
3376
3377 TEST_F(LibUAL, ApplicationId)
3378@@ -363,7 +405,6 @@
3379
3380 ASSERT_TRUE(upstart_app_launch_observer_add_app_started(observer_cb, &start_data));
3381 ASSERT_TRUE(upstart_app_launch_observer_add_app_stop(observer_cb, &stop_data));
3382- ASSERT_FALSE(upstart_app_launch_observer_add_app_failed(NULL, NULL)); /* Not yet implemented */
3383
3384 DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
3385
3386@@ -473,7 +514,6 @@
3387 /* Remove */
3388 ASSERT_TRUE(upstart_app_launch_observer_delete_app_started(observer_cb, &start_data));
3389 ASSERT_TRUE(upstart_app_launch_observer_delete_app_stop(observer_cb, &stop_data));
3390- ASSERT_FALSE(upstart_app_launch_observer_delete_app_failed(NULL, NULL)); /* Not yet implemented */
3391 }
3392
3393 static GDBusMessage *
3394@@ -527,3 +567,241 @@
3395 g_dbus_connection_remove_filter(session, filter);
3396 g_object_unref(session);
3397 }
3398+
3399+TEST_F(LibUAL, AppIdTest)
3400+{
3401+ ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
3402+ pause(50); /* Ensure all the events come through */
3403+ EXPECT_EQ("foo", this->last_focus_appid);
3404+ EXPECT_EQ("foo", this->last_resume_appid);
3405+}
3406+
3407+GDBusMessage *
3408+filter_func_good (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
3409+{
3410+ if (!incomming) {
3411+ return message;
3412+ }
3413+
3414+ if (g_strcmp0(g_dbus_message_get_path(message), (gchar *)user_data) == 0) {
3415+ GDBusMessage * reply = g_dbus_message_new_method_reply(message);
3416+ g_dbus_connection_send_message(conn, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
3417+ g_object_unref(message);
3418+ return NULL;
3419+ }
3420+
3421+ return message;
3422+}
3423+
3424+TEST_F(LibUAL, UrlSendTest)
3425+{
3426+ GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3427+ guint filter = g_dbus_connection_add_filter(session,
3428+ filter_func_good,
3429+ (gpointer)"/foo",
3430+ NULL);
3431+
3432+ const gchar * uris[] = {
3433+ "http://www.test.com",
3434+ NULL
3435+ };
3436+ ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
3437+ pause(100); /* Ensure all the events come through */
3438+
3439+ EXPECT_EQ("foo", this->last_focus_appid);
3440+ EXPECT_EQ("foo", this->last_resume_appid);
3441+
3442+ g_dbus_connection_remove_filter(session, filter);
3443+ g_object_unref(session);
3444+}
3445+
3446+TEST_F(LibUAL, UrlSendNoObjectTest)
3447+{
3448+ const gchar * uris[] = {
3449+ "http://www.test.com",
3450+ NULL
3451+ };
3452+
3453+ ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
3454+ pause(100); /* Ensure all the events come through */
3455+
3456+ EXPECT_EQ("foo", this->last_focus_appid);
3457+ EXPECT_EQ("foo", this->last_resume_appid);
3458+}
3459+
3460+TEST_F(LibUAL, UnityTimeoutTest)
3461+{
3462+ this->resume_timeout = 100;
3463+
3464+ ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
3465+ pause(1000); /* Ensure all the events come through */
3466+ EXPECT_EQ("foo", this->last_focus_appid);
3467+ EXPECT_EQ("foo", this->last_resume_appid);
3468+}
3469+
3470+TEST_F(LibUAL, UnityTimeoutUriTest)
3471+{
3472+ this->resume_timeout = 200;
3473+
3474+ const gchar * uris[] = {
3475+ "http://www.test.com",
3476+ NULL
3477+ };
3478+
3479+ ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
3480+ pause(1000); /* Ensure all the events come through */
3481+ EXPECT_EQ("foo", this->last_focus_appid);
3482+ EXPECT_EQ("foo", this->last_resume_appid);
3483+}
3484+
3485+GDBusMessage *
3486+filter_respawn (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
3487+{
3488+ if (g_strcmp0(g_dbus_message_get_member(message), "UnityResumeResponse") == 0) {
3489+ g_object_unref(message);
3490+ return NULL;
3491+ }
3492+
3493+ return message;
3494+}
3495+
3496+TEST_F(LibUAL, UnityLostTest)
3497+{
3498+ GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3499+ guint filter = g_dbus_connection_add_filter(session,
3500+ filter_respawn,
3501+ NULL,
3502+ NULL);
3503+
3504+ guint start = g_get_monotonic_time();
3505+
3506+ const gchar * uris[] = {
3507+ "http://www.test.com",
3508+ NULL
3509+ };
3510+
3511+ ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
3512+
3513+ guint end = g_get_monotonic_time();
3514+
3515+ EXPECT_LT(end - start, 600 * 1000);
3516+
3517+ pause(1000); /* Ensure all the events come through */
3518+
3519+ EXPECT_EQ("foo", this->last_focus_appid);
3520+ EXPECT_EQ("foo", this->last_resume_appid);
3521+
3522+ g_dbus_connection_remove_filter(session, filter);
3523+ g_object_unref(session);
3524+}
3525+
3526+
3527+TEST_F(LibUAL, LegacySingleInstance)
3528+{
3529+ DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
3530+
3531+ /* Check for a single-instance app */
3532+ ASSERT_TRUE(upstart_app_launch_start_application("single", NULL));
3533+
3534+ guint len = 0;
3535+ const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
3536+ EXPECT_NE(nullptr, calls);
3537+ EXPECT_EQ(1, len);
3538+
3539+ EXPECT_STREQ("Start", calls->name);
3540+ EXPECT_EQ(2, g_variant_n_children(calls->params));
3541+
3542+ GVariant * block = g_variant_get_child_value(calls->params, 1);
3543+ EXPECT_TRUE(g_variant_get_boolean(block));
3544+ g_variant_unref(block);
3545+
3546+ GVariant * env = g_variant_get_child_value(calls->params, 0);
3547+ EXPECT_TRUE(check_env(env, "APP_ID", "single"));
3548+ EXPECT_TRUE(check_env(env, "INSTANCE_ID", ""));
3549+ g_variant_unref(env);
3550+
3551+ ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
3552+
3553+ /* Check for a multi-instance app */
3554+ ASSERT_TRUE(upstart_app_launch_start_application("multiple", NULL));
3555+
3556+ len = 0;
3557+ calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
3558+ EXPECT_NE(nullptr, calls);
3559+ EXPECT_EQ(1, len);
3560+
3561+ EXPECT_STREQ("Start", calls->name);
3562+ EXPECT_EQ(2, g_variant_n_children(calls->params));
3563+
3564+ block = g_variant_get_child_value(calls->params, 1);
3565+ EXPECT_TRUE(g_variant_get_boolean(block));
3566+ g_variant_unref(block);
3567+
3568+ env = g_variant_get_child_value(calls->params, 0);
3569+ EXPECT_TRUE(check_env(env, "APP_ID", "multiple"));
3570+ EXPECT_FALSE(check_env(env, "INSTANCE_ID", ""));
3571+ g_variant_unref(env);
3572+}
3573+
3574+static void
3575+failed_observer (const gchar * appid, upstart_app_launch_app_failed_t reason, gpointer user_data)
3576+{
3577+ if (reason == UPSTART_APP_LAUNCH_APP_FAILED_CRASH) {
3578+ std::string * last = static_cast<std::string *>(user_data);
3579+ *last = appid;
3580+ }
3581+ return;
3582+}
3583+
3584+TEST_F(LibUAL, FailingObserver)
3585+{
3586+ std::string last_observer;
3587+ GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3588+
3589+ EXPECT_TRUE(upstart_app_launch_observer_add_app_failed(failed_observer, &last_observer));
3590+
3591+ g_dbus_connection_emit_signal(session,
3592+ NULL, /* destination */
3593+ "/", /* path */
3594+ "com.canonical.UpstartAppLaunch", /* interface */
3595+ "ApplicationFailed", /* signal */
3596+ g_variant_new("(ss)", "foo", "crash"), /* params, the same */
3597+ NULL);
3598+
3599+ pause(100);
3600+
3601+ EXPECT_EQ("foo", last_observer);
3602+
3603+ last_observer.clear();
3604+
3605+ g_dbus_connection_emit_signal(session,
3606+ NULL, /* destination */
3607+ "/", /* path */
3608+ "com.canonical.UpstartAppLaunch", /* interface */
3609+ "ApplicationFailed", /* signal */
3610+ g_variant_new("(ss)", "foo", "blahblah"), /* params, the same */
3611+ NULL);
3612+
3613+ pause(100);
3614+
3615+ EXPECT_EQ("foo", last_observer);
3616+
3617+ last_observer.clear();
3618+
3619+ g_dbus_connection_emit_signal(session,
3620+ NULL, /* destination */
3621+ "/", /* path */
3622+ "com.canonical.UpstartAppLaunch", /* interface */
3623+ "ApplicationFailed", /* signal */
3624+ g_variant_new("(ss)", "foo", "start-failure"), /* params, the same */
3625+ NULL);
3626+
3627+ pause(100);
3628+
3629+ EXPECT_TRUE(last_observer.empty());
3630+
3631+ EXPECT_TRUE(upstart_app_launch_observer_delete_app_failed(failed_observer, &last_observer));
3632+
3633+ g_object_unref(session);
3634+}
3635+
3636
3637=== added directory 'tests/link-farm'
3638=== added file 'tests/link-farm/README'
3639--- tests/link-farm/README 1970-01-01 00:00:00 +0000
3640+++ tests/link-farm/README 2014-02-11 03:28:22 +0000
3641@@ -0,0 +1,3 @@
3642+This directory is setup as our testing link farm. Anything that has a
3643+desktop in here will be detected as a click package, something without
3644+will be seen as a legacy package.
3645
3646=== added file 'tests/link-farm/foo.desktop'
3647--- tests/link-farm/foo.desktop 1970-01-01 00:00:00 +0000
3648+++ tests/link-farm/foo.desktop 2014-02-11 03:28:22 +0000
3649@@ -0,0 +1,1 @@
3650+Needs to exist
3651
3652=== added file 'tests/link-farm/foolike.desktop'
3653--- tests/link-farm/foolike.desktop 1970-01-01 00:00:00 +0000
3654+++ tests/link-farm/foolike.desktop 2014-02-11 03:28:22 +0000
3655@@ -0,0 +1,1 @@
3656+Needs to exist
3657
3658=== modified file 'tests/manual'
3659--- tests/manual 2014-01-30 22:13:28 +0000
3660+++ tests/manual 2014-02-11 03:28:22 +0000
3661@@ -27,3 +27,10 @@
3662 <dt>Send a URL to the service: <tt>upstart-app-launch ubuntu-system-settings settings:///system/battery</tt></dt>
3663 <dd>The settings application should come back into focus and be on the power settings pane</dd>
3664 </dl>
3665+
3666+Test-case upstart-app-launch/security-app-launch
3667+<dl>
3668+ <dt>Setup the security tests: https://wiki.ubuntu.com/Touch/Testing#Running_Security_tests</dt>
3669+ <dt>Execute the <tt>click-apparmor</tt> test to start and stop several confined applications</dt>
3670+ <dd>Ensure that all applications start and stop correctly</dd>
3671+</dl>
3672
3673=== removed file 'tests/second-exec-test.cc'
3674--- tests/second-exec-test.cc 2013-12-06 11:44:25 +0000
3675+++ tests/second-exec-test.cc 1970-01-01 00:00:00 +0000
3676@@ -1,205 +0,0 @@
3677-/*
3678- * Copyright 2013 Canonical Ltd.
3679- *
3680- * This program is free software: you can redistribute it and/or modify it
3681- * under the terms of the GNU General Public License version 3, as published
3682- * by the Free Software Foundation.
3683- *
3684- * This program is distributed in the hope that it will be useful, but
3685- * WITHOUT ANY WARRANTY; without even the implied warranties of
3686- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3687- * PURPOSE. See the GNU General Public License for more details.
3688- *
3689- * You should have received a copy of the GNU General Public License along
3690- * with this program. If not, see <http://www.gnu.org/licenses/>.
3691- *
3692- * Authors:
3693- * Ted Gould <ted.gould@canonical.com>
3694- */
3695-
3696-#include <gtest/gtest.h>
3697-#include <gio/gio.h>
3698-
3699-extern "C" {
3700-#include "../second-exec-core.h"
3701-#include "upstart-app-launch.h"
3702-#include "upstart-app-launch-mock.h"
3703-}
3704-
3705-class SecondExecTest : public ::testing::Test
3706-{
3707- private:
3708- GTestDBus * testbus = NULL;
3709-
3710- protected:
3711- std::string last_focus_appid;
3712- std::string last_resume_appid;
3713- guint resume_timeout = 0;
3714-
3715- private:
3716- static void focus_cb (const gchar * appid, gpointer user_data) {
3717- SecondExecTest * _this = static_cast<SecondExecTest *>(user_data);
3718- _this->last_focus_appid = appid;
3719- }
3720-
3721- static void resume_cb (const gchar * appid, gpointer user_data) {
3722- SecondExecTest * _this = static_cast<SecondExecTest *>(user_data);
3723- _this->last_resume_appid = appid;
3724-
3725- if (_this->resume_timeout > 0) {
3726- _this->pause(_this->resume_timeout);
3727- }
3728- }
3729-
3730- protected:
3731- virtual void SetUp() {
3732- testbus = g_test_dbus_new(G_TEST_DBUS_NONE);
3733- g_test_dbus_up(testbus);
3734-
3735- upstart_app_launch_observer_add_app_focus(focus_cb, this);
3736- upstart_app_launch_observer_add_app_resume(resume_cb, this);
3737- }
3738- virtual void TearDown() {
3739- upstart_app_launch_observer_delete_app_focus(focus_cb, this);
3740- upstart_app_launch_observer_delete_app_resume(resume_cb, this);
3741-
3742- g_test_dbus_down(testbus);
3743- g_object_unref(testbus);
3744- }
3745-
3746- static gboolean pause_helper (gpointer pmainloop) {
3747- g_main_loop_quit((GMainLoop *)pmainloop);
3748- return G_SOURCE_REMOVE;
3749- }
3750-
3751- void pause (guint time) {
3752- if (time > 0) {
3753- GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
3754- guint timer = g_timeout_add(time, pause_helper, mainloop);
3755-
3756- g_main_loop_run(mainloop);
3757-
3758- g_source_remove(timer);
3759- g_main_loop_unref(mainloop);
3760- }
3761-
3762- while (g_main_pending()) {
3763- g_main_iteration(TRUE);
3764- }
3765- }
3766-};
3767-
3768-TEST_F(SecondExecTest, AppIdTest)
3769-{
3770- ASSERT_TRUE(second_exec("foo", NULL));
3771- pause(50); /* Ensure all the events come through */
3772- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
3773- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
3774-}
3775-
3776-GDBusMessage *
3777-filter_func_good (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
3778-{
3779- if (!incomming) {
3780- return message;
3781- }
3782-
3783- if (g_strcmp0(g_dbus_message_get_path(message), (gchar *)user_data) == 0) {
3784- GDBusMessage * reply = g_dbus_message_new_method_reply(message);
3785- g_dbus_connection_send_message(conn, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
3786- g_object_unref(message);
3787- return NULL;
3788- }
3789-
3790- return message;
3791-}
3792-
3793-TEST_F(SecondExecTest, UrlSendTest)
3794-{
3795- upstart_app_launch_mock_set_primary_pid(getpid());
3796-
3797- GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3798- guint filter = g_dbus_connection_add_filter(session,
3799- filter_func_good,
3800- (gpointer)"/foo",
3801- NULL);
3802-
3803- ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
3804- pause(100); /* Ensure all the events come through */
3805-
3806- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
3807- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
3808-
3809- g_dbus_connection_remove_filter(session, filter);
3810- g_object_unref(session);
3811-}
3812-
3813-TEST_F(SecondExecTest, UrlSendNoObjectTest)
3814-{
3815- upstart_app_launch_mock_set_primary_pid(getpid());
3816-
3817- ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
3818- pause(100); /* Ensure all the events come through */
3819-
3820- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
3821- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
3822-}
3823-
3824-TEST_F(SecondExecTest, UnityTimeoutTest)
3825-{
3826- this->resume_timeout = 100;
3827-
3828- ASSERT_TRUE(second_exec("foo", NULL));
3829- pause(100); /* Ensure all the events come through */
3830- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
3831- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
3832-}
3833-
3834-TEST_F(SecondExecTest, UnityTimeoutUriTest)
3835-{
3836- this->resume_timeout = 200;
3837-
3838- ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
3839- pause(100); /* Ensure all the events come through */
3840- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
3841- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
3842-}
3843-
3844-GDBusMessage *
3845-filter_respawn (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
3846-{
3847- if (g_strcmp0(g_dbus_message_get_member(message), "UnityResumeResponse") == 0) {
3848- g_object_unref(message);
3849- return NULL;
3850- }
3851-
3852- return message;
3853-}
3854-
3855-TEST_F(SecondExecTest, UnityLostTest)
3856-{
3857- upstart_app_launch_mock_set_primary_pid(getpid());
3858-
3859- GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3860- guint filter = g_dbus_connection_add_filter(session,
3861- filter_respawn,
3862- NULL,
3863- NULL);
3864-
3865- guint start = g_get_monotonic_time();
3866-
3867- ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
3868-
3869- guint end = g_get_monotonic_time();
3870-
3871- ASSERT_LT(end - start, 600 * 1000);
3872-
3873- pause(100); /* Ensure all the events come through */
3874- ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
3875- ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
3876-
3877- g_dbus_connection_remove_filter(session, filter);
3878- g_object_unref(session);
3879-}
3880-
3881-
3882
3883=== modified file 'tests/zg-test.cc'
3884--- tests/zg-test.cc 2013-11-08 18:48:33 +0000
3885+++ tests/zg-test.cc 2014-02-11 03:28:22 +0000
3886@@ -66,3 +66,58 @@
3887 g_object_unref(mock);
3888 g_object_unref(service);
3889 }
3890+
3891+static void
3892+zg_state_changed (DbusTestTask * task, DbusTestTaskState state, gpointer user_data)
3893+{
3894+ if (state != DBUS_TEST_TASK_STATE_FINISHED)
3895+ return;
3896+
3897+ g_debug("ZG Event Task Finished");
3898+
3899+ GMainLoop * mainloop = static_cast<GMainLoop *>(user_data);
3900+ g_main_loop_quit(mainloop);
3901+}
3902+
3903+TEST(ZGEvent, TimeoutTest)
3904+{
3905+ GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
3906+ DbusTestService * service = dbus_test_service_new(NULL);
3907+
3908+ DbusTestDbusMock * mock = dbus_test_dbus_mock_new("org.gnome.zeitgeist.Engine");
3909+ DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/org/gnome/zeitgeist/log/activity", "org.gnome.zeitgeist.Log", NULL);
3910+
3911+ dbus_test_dbus_mock_object_add_method(mock, obj,
3912+ "InsertEvents",
3913+ G_VARIANT_TYPE("a(asaasay)"),
3914+ G_VARIANT_TYPE("au"),
3915+ "time.sleep(6)\n"
3916+ "ret = [ 0 ]",
3917+ NULL);
3918+
3919+ dbus_test_service_add_task(service, DBUS_TEST_TASK(mock));
3920+
3921+ DbusTestProcess * zgevent = dbus_test_process_new(ZG_EVENT_TOOL);
3922+ dbus_test_process_append_param(zgevent, "close");
3923+ g_setenv("APP_ID", "foo", 1);
3924+ dbus_test_task_set_wait_for(DBUS_TEST_TASK(zgevent), "org.gnome.zeitgeist.Engine");
3925+ dbus_test_task_set_name(DBUS_TEST_TASK(zgevent), "ZGEvent");
3926+ g_signal_connect(G_OBJECT(zgevent), DBUS_TEST_TASK_SIGNAL_STATE_CHANGED, G_CALLBACK(zg_state_changed), mainloop);
3927+
3928+ dbus_test_service_add_task(service, DBUS_TEST_TASK(zgevent));
3929+
3930+ guint64 start = g_get_monotonic_time();
3931+
3932+ dbus_test_service_start_tasks(service);
3933+
3934+ g_main_loop_run(mainloop);
3935+
3936+ guint64 end = g_get_monotonic_time();
3937+
3938+ /* Four seconds to do a two second op -- ARM Jenkins is slow */
3939+ EXPECT_LT(end - start, 4 * 1000 * 1000);
3940+
3941+ g_object_unref(zgevent);
3942+ g_object_unref(service);
3943+ g_main_loop_unref(mainloop);
3944+}
3945
3946=== modified file 'upstart-app-watch.c'
3947--- upstart-app-watch.c 2013-12-05 17:14:55 +0000
3948+++ upstart-app-watch.c 2014-02-11 03:28:22 +0000
3949@@ -67,7 +67,7 @@
3950 break;
3951 }
3952
3953- g_print("Fail %s (%s)\n", appid, failstr);
3954+ g_print("Fail %s (%s)\n", appid, failstr);
3955 return;
3956 }
3957
3958
3959=== modified file 'zg-report-app.c'
3960--- zg-report-app.c 2013-11-08 18:17:42 +0000
3961+++ zg-report-app.c 2014-02-11 03:28:22 +0000
3962@@ -23,7 +23,7 @@
3963 static gboolean
3964 watchdog_timeout (gpointer user_data)
3965 {
3966- g_error("Watchdog triggered, took too long to submit into Zeitgeist Database!");
3967+ g_warning("Watchdog triggered, took too long to submit into Zeitgeist Database!");
3968 g_main_loop_quit((GMainLoop *)user_data);
3969
3970 return G_SOURCE_REMOVE;
3971@@ -84,7 +84,7 @@
3972 GMainLoop * main_loop = g_main_loop_new(NULL, FALSE);
3973
3974 zeitgeist_log_insert_event(log, event, NULL, insert_complete, main_loop);
3975- g_timeout_add_seconds(4, watchdog_timeout, main_loop);
3976+ g_timeout_add_seconds(2, watchdog_timeout, main_loop);
3977
3978 g_main_loop_run(main_loop);
3979

Subscribers

People subscribed via source and target branches