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
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2014-01-06 15:21:25 +0000
+++ CMakeLists.txt 2014-02-11 03:28:22 +0000
@@ -9,6 +9,7 @@
9set(PACKAGE ${CMAKE_PROJECT_NAME})9set(PACKAGE ${CMAKE_PROJECT_NAME})
1010
11find_package(PkgConfig REQUIRED)11find_package(PkgConfig REQUIRED)
12find_package(GObjectIntrospection REQUIRED)
12include(GNUInstallDirs)13include(GNUInstallDirs)
13include(CheckIncludeFile)14include(CheckIncludeFile)
14include(CheckFunctionExists)15include(CheckFunctionExists)
@@ -51,9 +52,12 @@
51pkg_check_modules(ZEITGEIST REQUIRED zeitgeist-2.0)52pkg_check_modules(ZEITGEIST REQUIRED zeitgeist-2.0)
52include_directories(${ZEITGEIST_INCLUDE_DIRS})53include_directories(${ZEITGEIST_INCLUDE_DIRS})
5354
54pkg_check_modules(LIBUPSTART REQUIRED libupstart libnih libnih-dbus dbus-1)55pkg_check_modules(LIBUPSTART REQUIRED libupstart)
55include_directories(${LIBUPSTART_INCLUDE_DIRS})56include_directories(${LIBUPSTART_INCLUDE_DIRS})
5657
58pkg_check_modules(DBUS REQUIRED dbus-1)
59include_directories(${DBUS_INCLUDE_DIRS})
60
57pkg_check_modules(DBUSTEST REQUIRED dbustest-1>=14.04.0)61pkg_check_modules(DBUSTEST REQUIRED dbustest-1>=14.04.0)
58include_directories(${DBUSTEST_INCLUDE_DIRS})62include_directories(${DBUSTEST_INCLUDE_DIRS})
5963
@@ -68,7 +72,7 @@
68# Helpers72# Helpers
69####################73####################
7074
71add_library(helpers STATIC helpers.c)75add_library(helpers STATIC helpers.c helpers-keyfile.c)
72target_link_libraries(helpers ${GIO2_LIBRARIES} ${JSONGLIB_LIBRARIES})76target_link_libraries(helpers ${GIO2_LIBRARIES} ${JSONGLIB_LIBRARIES})
7377
74####################78####################
@@ -146,16 +150,6 @@
146install(TARGETS desktop-hook RUNTIME DESTINATION "${pkglibexecdir}")150install(TARGETS desktop-hook RUNTIME DESTINATION "${pkglibexecdir}")
147151
148####################152####################
149# desktop-single
150####################
151
152add_lttng_gen_tp(NAME desktop-single-trace)
153add_executable(desktop-single desktop-single.c desktop-single-trace.c)
154set_target_properties(desktop-single PROPERTIES OUTPUT_NAME "desktop-single")
155target_link_libraries(desktop-single helpers ${LTTNG_LIBRARIES})
156install(TARGETS desktop-single RUNTIME DESTINATION "${pkglibexecdir}")
157
158####################
159# exec-line-exec153# exec-line-exec
160####################154####################
161155
@@ -175,18 +169,23 @@
175target_link_libraries(zg-report-app ${ZEITGEIST_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GLIB2_LIBRARIES})169target_link_libraries(zg-report-app ${ZEITGEIST_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GLIB2_LIBRARIES})
176install(TARGETS zg-report-app RUNTIME DESTINATION "${pkglibexecdir}")170install(TARGETS zg-report-app RUNTIME DESTINATION "${pkglibexecdir}")
177171
178#######################172####################
179# second-exec173# application-job
180#######################174####################
181175
182add_lttng_gen_tp(NAME second-exec-trace)176add_executable(application-job application-job.c)
183add_library(second-exec-core STATIC second-exec-core.c second-exec-trace.c)177set_target_properties(application-job PROPERTIES OUTPUT_NAME "application-job")
184target_link_libraries(second-exec-core helpers upstart-launcher ${LTTNG_LIBRARIES})178target_link_libraries(application-job upstart-launcher)
185179install(TARGETS application-job RUNTIME DESTINATION "${pkglibexecdir}")
186add_executable(second-exec second-exec.c)180
187set_target_properties(second-exec PROPERTIES OUTPUT_NAME "second-exec")181####################
188target_link_libraries(second-exec second-exec-core)182# application-failed
189install(TARGETS second-exec RUNTIME DESTINATION "${pkglibexecdir}")183####################
184
185add_executable(application-failed application-failed.c)
186set_target_properties(application-failed PROPERTIES OUTPUT_NAME "application-failed")
187target_link_libraries(application-failed ${GIO2_LIBRARIES})
188install(TARGETS application-failed RUNTIME DESTINATION "${pkglibexecdir}")
190189
191####################190####################
192# application.conf191# application.conf
@@ -213,6 +212,14 @@
213add_test(application-click.conf.test "${CMAKE_SOURCE_DIR}/test-conffile.sh" "${CMAKE_CURRENT_BINARY_DIR}/application-click.conf")212add_test(application-click.conf.test "${CMAKE_SOURCE_DIR}/test-conffile.sh" "${CMAKE_CURRENT_BINARY_DIR}/application-click.conf")
214213
215####################214####################
215# application-failed.conf
216####################
217
218configure_file("application-failed.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/application-failed.conf" @ONLY)
219install(FILES "${CMAKE_CURRENT_BINARY_DIR}/application-failed.conf" DESTINATION "${CMAKE_INSTALL_DATADIR}/upstart/sessions")
220add_test(application-failed.conf.test "${CMAKE_SOURCE_DIR}/test-conffile.sh" "${CMAKE_CURRENT_BINARY_DIR}/application-failed.conf")
221
222####################
216# upstart-app-launch-desktop.click-hook223# upstart-app-launch-desktop.click-hook
217####################224####################
218225
219226
=== added file 'application-failed.c'
--- application-failed.c 1970-01-01 00:00:00 +0000
+++ application-failed.c 2014-02-11 03:28:22 +0000
@@ -0,0 +1,72 @@
1
2/*
3 * Copyright 2013 Canonical Ltd.
4 *
5 * This program is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 3, as published
7 * by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranties of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors:
18 * Ted Gould <ted.gould@canonical.com>
19 */
20
21#include <gio/gio.h>
22
23int
24main (int argc, char * argv[])
25{
26 const gchar * job = g_getenv("JOB");
27 g_return_val_if_fail(job != NULL, -1);
28
29 const gchar * instance = g_getenv("INSTANCE");
30 g_return_val_if_fail(instance != NULL, -1);
31
32 gboolean crashed = FALSE;
33 if (g_getenv("EXIT_STATUS") != NULL || g_getenv("EXIT_SIGNAL") != NULL) {
34 crashed = TRUE;
35 }
36
37 gchar * appid = g_strdup(instance);
38 if (g_strcmp0(job, "application-legacy") == 0) {
39 gchar * lasthyphenstanding = g_strrstr(appid, "-");
40 if (lasthyphenstanding != NULL) {
41 lasthyphenstanding[0] = '\0';
42 } else {
43 g_warning("Legacy job instance '%s' is missing a hyphen", appid);
44 }
45 }
46
47 GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
48 g_return_val_if_fail(bus != NULL, -1);
49
50 GError * error = NULL;
51 g_dbus_connection_emit_signal(bus,
52 NULL, /* destination */
53 "/", /* path */
54 "com.canonical.UpstartAppLaunch",
55 "ApplicationFailed",
56 g_variant_new("(ss)", appid, crashed ? "crash" : "start-failure"),
57 &error);
58
59 g_debug("Emitting failed event '%s' for app '%s'", crashed ? "crash" : "start-failure", appid);
60
61 if (error != NULL) {
62 g_warning("Unable to emit signal: %s", error->message);
63 g_error_free(error);
64 return -1;
65 }
66
67 g_dbus_connection_flush_sync(bus, NULL, NULL);
68 g_object_unref(bus);
69 g_free(appid);
70
71 return 0;
72}
073
=== added file 'application-failed.conf.in'
--- application-failed.conf.in 1970-01-01 00:00:00 +0000
+++ application-failed.conf.in 2014-02-11 03:28:22 +0000
@@ -0,0 +1,6 @@
1description "Application Failing"
2
3start on stopped application-legacy RESULT=failed or stopped application-click RESULT=failed
4task
5
6exec @pkglibexecdir@/application-failed
07
=== added file 'application-job.c'
--- application-job.c 1970-01-01 00:00:00 +0000
+++ application-job.c 2014-02-11 03:28:22 +0000
@@ -0,0 +1,113 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#include <gio/gio.h>
21#include "libupstart-app-launch/upstart-app-launch.h"
22
23int retval = 0;
24const gchar * global_appid;
25
26static void
27app_started (const gchar * appid, gpointer user_data)
28{
29 if (g_strcmp0(appid, global_appid) != 0)
30 return;
31 g_debug("Application Started: %s", appid);
32 g_main_loop_quit((GMainLoop *)user_data);
33}
34
35static void
36app_focus (const gchar * appid, gpointer user_data)
37{
38 if (g_strcmp0(appid, global_appid) != 0)
39 return;
40 g_debug("Application Focused");
41 g_main_loop_quit((GMainLoop *)user_data);
42}
43
44static void
45app_failed (const gchar * appid, upstart_app_launch_app_failed_t failure_type, gpointer user_data)
46{
47 if (g_strcmp0(appid, global_appid) != 0)
48 return;
49 g_warning("Application Startup Failed");
50 retval = 1;
51 g_main_loop_quit((GMainLoop *)user_data);
52}
53
54/* A fallback so that we can see what is going on. The job can not always signal
55 that it has been started, and thus we wouldn't quit. Which would be a bad thing. */
56static gboolean
57timeout_check (gpointer user_data)
58{
59 g_debug("Timeout reached");
60 g_main_loop_quit((GMainLoop *)user_data);
61 return TRUE; /* Keep the source connected to avoid the disconnect error */
62}
63
64int
65main (int argc, char * argv[])
66{
67 GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
68 g_return_val_if_fail(con != NULL, 1);
69
70 global_appid = g_getenv("APP_ID");
71 g_return_val_if_fail(global_appid != NULL, 1);
72
73 const gchar * uris_str = g_getenv("APP_URIS");
74 gchar ** uris = NULL;
75 if (uris_str != NULL) {
76 GError * error = NULL;
77 gint uri_count = 0;
78 g_shell_parse_argv(uris_str, &uri_count, &uris, &error);
79
80 if (error != NULL) {
81 g_warning("Unable to parse uris '%s': %s", uris_str, error->message);
82 g_error_free(error);
83 } else {
84 g_debug("Got %d URIs", uri_count);
85 }
86 }
87
88 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
89
90 upstart_app_launch_observer_add_app_started(app_started, mainloop);
91 upstart_app_launch_observer_add_app_focus(app_focus, mainloop);
92 upstart_app_launch_observer_add_app_failed(app_failed, mainloop);
93
94 guint timer = g_timeout_add_seconds(1, timeout_check, mainloop);
95
96 g_debug("Start Application: %s", global_appid);
97 g_return_val_if_fail(upstart_app_launch_start_application(global_appid, (const gchar * const *)uris), -1);
98 g_strfreev(uris);
99
100 g_debug("Wait for results");
101 g_main_loop_run(mainloop);
102
103 g_source_remove(timer);
104
105 upstart_app_launch_observer_delete_app_started(app_started, mainloop);
106 upstart_app_launch_observer_delete_app_focus(app_focus, mainloop);
107 upstart_app_launch_observer_delete_app_failed(app_failed, mainloop);
108
109 g_main_loop_unref(mainloop);
110 g_object_unref(con);
111
112 return retval;
113}
0114
=== modified file 'application.conf.in'
--- application.conf.in 2014-01-22 22:48:58 +0000
+++ application.conf.in 2014-02-11 03:28:22 +0000
@@ -14,24 +14,4 @@
14env APP_URIS14env APP_URIS
15export APP_URIS15export APP_URIS
1616
17script17exec @pkglibexecdir@/application-job
18 CLICK_PKG=`echo "${APP_ID}" | cut -d _ -f 1`
19
20 if [ ! -z $CLICK_PKG ] ; then
21 CLICK_DIR=`click pkgdir "${CLICK_PKG}" 2> /dev/null || true`
22 fi
23
24 if [ ! -z $CLICK_DIR ] && [ -d $CLICK_DIR ] ; then
25 if ! start application-click APP_ID="${APP_ID}" APP_URIS="${APP_URIS}"; then
26 @pkglibexecdir@/second-exec
27 fi
28 else
29 if @pkglibexecdir@/desktop-single $APP_ID ; then
30 if ! start application-legacy APP_ID="${APP_ID}" INSTANCE_ID="" APP_URIS="${APP_URIS}" ; then
31 @pkglibexecdir@/second-exec
32 fi
33 else
34 start application-legacy APP_ID="${APP_ID}" INSTANCE_ID=`date -u +%s` APP_URIS="${APP_URIS}"
35 fi
36 fi
37end script
3818
=== added file 'cmake/FindGObjectIntrospection.cmake'
--- cmake/FindGObjectIntrospection.cmake 1970-01-01 00:00:00 +0000
+++ cmake/FindGObjectIntrospection.cmake 2014-02-11 03:28:22 +0000
@@ -0,0 +1,61 @@
1# - try to find gobject-introspection
2#
3# Once done this will define
4#
5# INTROSPECTION_FOUND - system has gobject-introspection
6# INTROSPECTION_SCANNER - the gobject-introspection scanner, g-ir-scanner
7# INTROSPECTION_COMPILER - the gobject-introspection compiler, g-ir-compiler
8# INTROSPECTION_GENERATE - the gobject-introspection generate, g-ir-generate
9# INTROSPECTION_GIRDIR
10# INTROSPECTION_TYPELIBDIR
11# INTROSPECTION_CFLAGS
12# INTROSPECTION_LIBS
13#
14# Copyright (C) 2010, Pino Toscano, <pino@kde.org>
15#
16# Redistribution and use is allowed according to the terms of the BSD license.
17# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
18
19macro(_GIR_GET_PKGCONFIG_VAR _outvar _varname)
20 execute_process(
21 COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=${_varname} gobject-introspection-1.0
22 OUTPUT_VARIABLE _result
23 RESULT_VARIABLE _null
24 )
25
26 if (_null)
27 else()
28 string(REGEX REPLACE "[\r\n]" " " _result "${_result}")
29 string(REGEX REPLACE " +$" "" _result "${_result}")
30 separate_arguments(_result)
31 set(${_outvar} ${_result} CACHE INTERNAL "")
32 endif()
33endmacro(_GIR_GET_PKGCONFIG_VAR)
34
35find_package(PkgConfig)
36if(PKG_CONFIG_FOUND)
37 if(PACKAGE_FIND_VERSION_COUNT GREATER 0)
38 set(_gir_version_cmp ">=${PACKAGE_FIND_VERSION}")
39 endif()
40 pkg_check_modules(_pc_gir gobject-introspection-1.0${_gir_version_cmp})
41 if(_pc_gir_FOUND)
42 set(INTROSPECTION_FOUND TRUE)
43 _gir_get_pkgconfig_var(INTROSPECTION_SCANNER "g_ir_scanner")
44 _gir_get_pkgconfig_var(INTROSPECTION_COMPILER "g_ir_compiler")
45 _gir_get_pkgconfig_var(INTROSPECTION_GENERATE "g_ir_generate")
46 _gir_get_pkgconfig_var(INTROSPECTION_GIRDIR "girdir")
47 _gir_get_pkgconfig_var(INTROSPECTION_TYPELIBDIR "typelibdir")
48 set(INTROSPECTION_CFLAGS "${_pc_gir_CFLAGS}")
49 set(INTROSPECTION_LIBS "${_pc_gir_LIBS}")
50 endif()
51endif()
52
53mark_as_advanced(
54 INTROSPECTION_SCANNER
55 INTROSPECTION_COMPILER
56 INTROSPECTION_GENERATE
57 INTROSPECTION_GIRDIR
58 INTROSPECTION_TYPELIBDIR
59 INTROSPECTION_CFLAGS
60 INTROSPECTION_LIBS
61)
062
=== added file 'cmake/ListOperations.cmake'
--- cmake/ListOperations.cmake 1970-01-01 00:00:00 +0000
+++ cmake/ListOperations.cmake 2014-02-11 03:28:22 +0000
@@ -0,0 +1,18 @@
1
2macro(list_prefix _outvar _listvar _prefix)
3 set(${_outvar})
4 foreach(_item IN LISTS ${_listvar})
5 list(APPEND ${_outvar} ${_prefix}${_item})
6 endforeach()
7endmacro(list_prefix)
8
9macro(list_make_absolute _outvar _listvar _prefix)
10 set(${_outvar})
11 foreach(_item IN LISTS ${_listvar})
12 if(IS_ABSOLUTE ${_item})
13 list(APPEND ${_outvar} ${_item})
14 else()
15 list(APPEND ${_outvar} ${_prefix}${_item})
16 endif()
17 endforeach()
18endmacro(list_make_absolute)
019
=== added file 'cmake/UseGObjectIntrospection.cmake'
--- cmake/UseGObjectIntrospection.cmake 1970-01-01 00:00:00 +0000
+++ cmake/UseGObjectIntrospection.cmake 2014-02-11 03:28:22 +0000
@@ -0,0 +1,102 @@
1# Copyright (C) 2010, Pino Toscano, <pino@kde.org>
2#
3# Redistribution and use is allowed according to the terms of the BSD license.
4# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
5
6include(ListOperations)
7
8macro(_gir_list_prefix _outvar _listvar _prefix)
9 set(${_outvar})
10 foreach(_item IN LISTS ${_listvar})
11 list(APPEND ${_outvar} ${_prefix}${_item})
12 endforeach()
13endmacro(_gir_list_prefix)
14
15macro(gir_add_introspections introspections_girs)
16
17 foreach(gir IN LISTS ${introspections_girs})
18
19 set(_gir_name "${gir}")
20
21 ## Transform the gir filename to something which can reference through a variable
22 ## without automake/make complaining, eg Gtk-2.0.gir -> Gtk_2_0_gir
23 string(REPLACE "-" "_" _gir_name "${_gir_name}")
24 string(REPLACE "." "_" _gir_name "${_gir_name}")
25
26 # Namespace and Version is either fetched from the gir filename
27 # or the _NAMESPACE/_VERSION variable combo
28 set(_gir_namespace "${${_gir_name}_NAMESPACE}")
29 if (_gir_namespace STREQUAL "")
30 string(REGEX REPLACE "([^-]+)-.*" "\\1" _gir_namespace "${gir}")
31 endif ()
32 set(_gir_version "${${_gir_name}_VERSION}")
33 if (_gir_version STREQUAL "")
34 string(REGEX REPLACE ".*-([^-]+).gir" "\\1" _gir_version "${gir}")
35 endif ()
36
37 # _PROGRAM is an optional variable which needs it's own --program argument
38 set(_gir_program "${${_gir_name}_PROGRAM}")
39 if (NOT _gir_program STREQUAL "")
40 set(_gir_program "--program=${_gir_program}")
41 endif ()
42
43 # Variables which provides a list of things
44 _gir_list_prefix(_gir_libraries ${_gir_name}_LIBS "--library=")
45 _gir_list_prefix(_gir_packages ${_gir_name}_PACKAGES "--pkg=")
46 _gir_list_prefix(_gir_includes ${_gir_name}_INCLUDES "--include=")
47 _gir_list_prefix(_gir_export_packages ${_gir_name}_EXPORT_PACKAGES "--pkg-export=")
48
49 # Reuse the LIBTOOL variable from by automake if it's set
50 set(_gir_libtool "--no-libtool")
51
52 add_custom_command(
53 COMMAND ${INTROSPECTION_SCANNER}
54 ${INTROSPECTION_SCANNER_ARGS}
55 --quiet
56 --warn-all
57 --namespace=${_gir_namespace}
58 --nsversion=${_gir_version}
59 ${_gir_libtool}
60 ${_gir_program}
61 ${_gir_libraries}
62 ${_gir_packages}
63 ${_gir_includes}
64 ${_gir_export_packages}
65 ${${_gir_name}_SCANNERFLAGS}
66 ${${_gir_name}_CFLAGS}
67 ${${_gir_name}_FILES}
68 --output ${CMAKE_CURRENT_BINARY_DIR}/${gir}
69 DEPENDS ${${_gir_name}_FILES}
70 ${${_gir_name}_LIBS}
71 OUTPUT ${gir}
72 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
73 VERBATIM
74 )
75 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${gir} DESTINATION share/gir-1.0)
76
77 string(REPLACE ".gir" ".typelib" _typelib "${gir}")
78 add_custom_command(
79 COMMAND ${INTROSPECTION_COMPILER}
80 ${INTROSPECTION_COMPILER_ARGS}
81 --includedir=.
82 ${CMAKE_CURRENT_BINARY_DIR}/${gir}
83 -o ${CMAKE_CURRENT_BINARY_DIR}/${_typelib}
84 DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${gir}
85 OUTPUT ${_typelib}
86 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
87 )
88 install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_typelib} DESTINATION ${CMAKE_INSTALL_LIBDIR}/girepository-1.0)
89
90 add_custom_target(gir-${gir} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${gir})
91 add_custom_target(gir-typelibs-${_typelib} ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${_typelib})
92 endforeach()
93
94endmacro(gir_add_introspections)
95
96macro(gir_get_cflags _output)
97 get_directory_property(_tmp_includes INCLUDE_DIRECTORIES)
98 list_prefix(_includes _tmp_includes "-I")
99 get_directory_property(_tmp_compile_definitions COMPILE_DEFINITIONS)
100 list_prefix(_compile_definitions _tmp_compile_definitions "-D")
101 set(${_output} ${_includes} ${_compile_definitions})
102endmacro(gir_get_cflags)
0103
=== modified file 'data/com.canonical.UpstartAppLaunch.xml'
--- data/com.canonical.UpstartAppLaunch.xml 2013-12-06 10:48:02 +0000
+++ data/com.canonical.UpstartAppLaunch.xml 2014-02-11 03:28:22 +0000
@@ -16,5 +16,9 @@
16 <signal name="UnityStartingSignal">16 <signal name="UnityStartingSignal">
17 <arg type="s" name="appid" />17 <arg type="s" name="appid" />
18 </signal>18 </signal>
19 <signal name="ApplicationFailed">
20 <arg type="s" name="appid" />
21 <arg type="s" name="stage" />
22 </signal>
19 </interface>23 </interface>
20</node>24</node>
2125
=== modified file 'debian/changelog'
--- debian/changelog 2014-02-06 16:54:55 +0000
+++ debian/changelog 2014-02-11 03:28:22 +0000
@@ -1,3 +1,9 @@
1upstart-app-launch (0.3+14.04.20140210-0ubuntu1) trusty; urgency=low
2
3 *
4
5 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Mon, 10 Feb 2014 10:25:19 +0000
6
1upstart-app-launch (0.3+14.04.20140206-0ubuntu1) trusty; urgency=low7upstart-app-launch (0.3+14.04.20140206-0ubuntu1) trusty; urgency=low
28
3 [ Ted Gould ]9 [ Ted Gould ]
410
=== modified file 'debian/control'
--- debian/control 2014-01-13 15:16:24 +0000
+++ debian/control 2014-02-11 03:28:22 +0000
@@ -9,6 +9,7 @@
9 debhelper (>= 9),9 debhelper (>= 9),
10 libdbus-1-dev,10 libdbus-1-dev,
11 libdbustest1-dev (>= 14.04.0),11 libdbustest1-dev (>= 14.04.0),
12 libgirepository1.0-dev,
12 libglib2.0-dev,13 libglib2.0-dev,
13 libgtest-dev,14 libgtest-dev,
14 libjson-glib-dev,15 libjson-glib-dev,
@@ -17,6 +18,7 @@
17 libnih-dev,18 libnih-dev,
18 libupstart-dev,19 libupstart-dev,
19 libzeitgeist-2.0-dev,20 libzeitgeist-2.0-dev,
21 gobject-introspection,
20 python3-dbusmock,22 python3-dbusmock,
21 upstart (>= 1.11),23 upstart (>= 1.11),
22Standards-Version: 3.9.424Standards-Version: 3.9.4
@@ -80,3 +82,18 @@
80 .82 .
81 This package contains files that are needed to build applications.83 This package contains files that are needed to build applications.
8284
85Package: gir1.2-upstart-app-launch-2
86Section: libs
87Architecture: any
88Depends: ${shlibs:Depends},
89 ${misc:Depends},
90 libupstart-app-launch2 (= ${binary:Version}),
91 ${gir:Depends},
92Pre-Depends: ${misc:Pre-Depends}
93Recommends: upstart-app-launch (= ${binary:Version})
94Description: typelib file for libupstart-app-launch2
95 Interface for starting apps and getting info on them.
96 .
97 This package can be used by other packages using the GIRepository format to
98 generate dynamic bindings for libupstart-app-launch2.
99
83100
=== added file 'debian/gir1.2-upstart-app-launch-2.install'
--- debian/gir1.2-upstart-app-launch-2.install 1970-01-01 00:00:00 +0000
+++ debian/gir1.2-upstart-app-launch-2.install 2014-02-11 03:28:22 +0000
@@ -0,0 +1,1 @@
1usr/lib/*/girepository-1.0 /usr/lib
02
=== modified file 'debian/libupstart-app-launch2-dev.install'
--- debian/libupstart-app-launch2-dev.install 2013-12-05 17:19:45 +0000
+++ debian/libupstart-app-launch2-dev.install 2014-02-11 03:28:22 +0000
@@ -1,3 +1,4 @@
1usr/lib/*/libupstart-app-launch.so1usr/lib/*/libupstart-app-launch.so
2usr/lib/*/pkgconfig/*2usr/lib/*/pkgconfig/*
3usr/include/*3usr/include/*
4usr/share/gir-1.0/*
45
=== modified file 'debian/rules'
--- debian/rules 2013-07-24 16:57:23 +0000
+++ debian/rules 2014-02-11 03:28:22 +0000
@@ -5,7 +5,7 @@
5#export DH_VERBOSE=15#export DH_VERBOSE=1
66
7%:7%:
8 dh $@ --with click8 dh $@ --with click,gir
99
10override_dh_click:10override_dh_click:
11 dh_click --name upstart-app-launch-desktop11 dh_click --name upstart-app-launch-desktop
1212
=== removed file 'desktop-single-trace.tp'
--- desktop-single-trace.tp 2013-12-04 17:10:57 +0000
+++ desktop-single-trace.tp 1970-01-01 00:00:00 +0000
@@ -1,5 +0,0 @@
1
2TRACEPOINT_EVENT(upstart_app_launch, desktop_single_start, TP_ARGS(0), TP_FIELDS())
3TRACEPOINT_EVENT(upstart_app_launch, desktop_single_found, TP_ARGS(0), TP_FIELDS())
4TRACEPOINT_EVENT(upstart_app_launch, desktop_single_finished, TP_ARGS(0), TP_FIELDS())
5
60
=== removed file 'desktop-single.c'
--- desktop-single.c 2013-12-05 17:08:13 +0000
+++ desktop-single.c 1970-01-01 00:00:00 +0000
@@ -1,68 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#include "helpers.h"
21#include "desktop-single-trace.h"
22
23int
24main (int argc, char * argv[])
25{
26 /* Nothing is single instance yet */
27 if (argc != 2) {
28 g_error("Should be called as: %s <app_id>", argv[0]);
29 return 1;
30 }
31
32 g_setenv("LTTNG_UST_REGISTER_TIMEOUT", "0", FALSE); /* Set to zero if not set */
33 tracepoint(upstart_app_launch, desktop_single_start);
34
35 GKeyFile * keyfile = keyfile_for_appid(argv[1], NULL);
36
37 if (keyfile == NULL) {
38 g_error("Unable to find keyfile for application '%s'", argv[0]);
39 return 1;
40 }
41
42 tracepoint(upstart_app_launch, desktop_single_found);
43
44 gboolean singleinstance = FALSE;
45
46 if (g_key_file_has_key(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", NULL)) {
47 GError * error = NULL;
48
49 singleinstance = g_key_file_get_boolean(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", &error);
50
51 if (error != NULL) {
52 g_warning("Unable to get single instance key for app '%s': %s", argv[1], error->message);
53 g_error_free(error);
54 /* Ensure that if we got an error, we assume standard case */
55 singleinstance = FALSE;
56 }
57 }
58
59 g_key_file_free(keyfile);
60
61 tracepoint(upstart_app_launch, desktop_single_finished);
62
63 if (singleinstance) {
64 return 0;
65 } else {
66 return 1;
67 }
68}
690
=== added file 'helpers-keyfile.c'
--- helpers-keyfile.c 1970-01-01 00:00:00 +0000
+++ helpers-keyfile.c 2014-02-11 03:28:22 +0000
@@ -0,0 +1,95 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#include "helpers.h"
21
22/* Check to make sure we have the sections and keys we want */
23static gboolean
24verify_keyfile (GKeyFile * inkeyfile, const gchar * desktop)
25{
26 if (inkeyfile == NULL) return FALSE;
27
28 if (!g_key_file_has_group(inkeyfile, "Desktop Entry")) {
29 g_warning("Desktop file '%s' is missing the 'Desktop Entry' group", desktop);
30 return FALSE;
31 }
32
33 if (!g_key_file_has_key(inkeyfile, "Desktop Entry", "Exec", NULL)) {
34 g_warning("Desktop file '%s' is missing the 'Exec' key", desktop);
35 return FALSE;
36 }
37
38 return TRUE;
39}
40
41/* Try to find a desktop file in a particular data directory */
42static GKeyFile *
43try_dir (const char * dir, const gchar * desktop)
44{
45 gchar * fullpath = g_build_filename(dir, "applications", desktop, NULL);
46 GKeyFile * keyfile = g_key_file_new();
47
48 /* NOTE: Leaving off the error here as we'll get a bunch of them,
49 so individuals aren't really useful */
50 gboolean loaded = g_key_file_load_from_file(keyfile, fullpath, G_KEY_FILE_NONE, NULL);
51
52 g_free(fullpath);
53
54 if (!loaded) {
55 g_key_file_free(keyfile);
56 return NULL;
57 }
58
59 if (!verify_keyfile(keyfile, desktop)) {
60 g_key_file_free(keyfile);
61 return NULL;
62 }
63
64 return keyfile;
65}
66
67/* Find the keyfile that we need for a particular AppID and return it.
68 Or NULL if we can't find it. */
69GKeyFile *
70keyfile_for_appid (const gchar * appid, gchar ** desktopfile)
71{
72 gchar * desktop = g_strdup_printf("%s.desktop", appid);
73
74 const char * const * data_dirs = g_get_system_data_dirs();
75 GKeyFile * keyfile = NULL;
76 int i;
77
78 keyfile = try_dir(g_get_user_data_dir(), desktop);
79 if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
80 *desktopfile = g_build_filename(g_get_user_data_dir(), "applications", desktop, NULL);
81 }
82
83 for (i = 0; data_dirs[i] != NULL && keyfile == NULL; i++) {
84 keyfile = try_dir(data_dirs[i], desktop);
85
86 if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
87 *desktopfile = g_build_filename(data_dirs[i], "applications", desktop, NULL);
88 }
89 }
90
91 g_free(desktop);
92
93 return keyfile;
94}
95
096
=== modified file 'helpers.c'
--- helpers.c 2014-02-03 18:29:54 +0000
+++ helpers.c 2014-02-11 03:28:22 +0000
@@ -492,80 +492,6 @@
492 return newargv;492 return newargv;
493}493}
494494
495/* Check to make sure we have the sections and keys we want */
496static gboolean
497verify_keyfile (GKeyFile * inkeyfile, const gchar * desktop)
498{
499 if (inkeyfile == NULL) return FALSE;
500
501 if (!g_key_file_has_group(inkeyfile, "Desktop Entry")) {
502 g_warning("Desktop file '%s' is missing the 'Desktop Entry' group", desktop);
503 return FALSE;
504 }
505
506 if (!g_key_file_has_key(inkeyfile, "Desktop Entry", "Exec", NULL)) {
507 g_warning("Desktop file '%s' is missing the 'Exec' key", desktop);
508 return FALSE;
509 }
510
511 return TRUE;
512}
513
514/* Try to find a desktop file in a particular data directory */
515static GKeyFile *
516try_dir (const char * dir, const gchar * desktop)
517{
518 gchar * fullpath = g_build_filename(dir, "applications", desktop, NULL);
519 GKeyFile * keyfile = g_key_file_new();
520
521 /* NOTE: Leaving off the error here as we'll get a bunch of them,
522 so individuals aren't really useful */
523 gboolean loaded = g_key_file_load_from_file(keyfile, fullpath, G_KEY_FILE_NONE, NULL);
524
525 g_free(fullpath);
526
527 if (!loaded) {
528 g_key_file_free(keyfile);
529 return NULL;
530 }
531
532 if (!verify_keyfile(keyfile, desktop)) {
533 g_key_file_free(keyfile);
534 return NULL;
535 }
536
537 return keyfile;
538}
539
540/* Find the keyfile that we need for a particular AppID and return it.
541 Or NULL if we can't find it. */
542GKeyFile *
543keyfile_for_appid (const gchar * appid, gchar ** desktopfile)
544{
545 gchar * desktop = g_strdup_printf("%s.desktop", appid);
546
547 const char * const * data_dirs = g_get_system_data_dirs();
548 GKeyFile * keyfile = NULL;
549 int i;
550
551 keyfile = try_dir(g_get_user_data_dir(), desktop);
552 if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
553 *desktopfile = g_build_filename(g_get_user_data_dir(), "applications", desktop, NULL);
554 }
555
556 for (i = 0; data_dirs[i] != NULL && keyfile == NULL; i++) {
557 keyfile = try_dir(data_dirs[i], desktop);
558
559 if (keyfile != NULL && desktopfile != NULL && *desktopfile == NULL) {
560 *desktopfile = g_build_filename(data_dirs[i], "applications", desktop, NULL);
561 }
562 }
563
564 g_free(desktop);
565
566 return keyfile;
567}
568
569/* Set environment various variables to make apps work under495/* Set environment various variables to make apps work under
570 * confinement according to:496 * confinement according to:
571 * https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement497 * https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement
572498
=== modified file 'libupstart-app-launch/CMakeLists.txt'
--- libupstart-app-launch/CMakeLists.txt 2014-01-13 15:16:24 +0000
+++ libupstart-app-launch/CMakeLists.txt 2014-02-11 03:28:22 +0000
@@ -1,4 +1,7 @@
11
2include_directories(${CMAKE_CURRENT_SOURCE_DIR})
3include_directories(${CMAKE_CURRENT_BINARY_DIR})
4
2##########################5##########################
3# Version Info6# Version Info
4##########################7##########################
@@ -11,6 +14,8 @@
11# Library14# Library
12##########################15##########################
1316
17add_lttng_gen_tp(NAME upstart-app-launch-trace)
18
14set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")19set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
1520
16set(LAUNCHER_HEADERS21set(LAUNCHER_HEADERS
@@ -19,6 +24,9 @@
1924
20set(LAUNCHER_SOURCES25set(LAUNCHER_SOURCES
21upstart-app-launch.c26upstart-app-launch.c
27second-exec-core.c
28upstart-app-launch-trace.c
29"${CMAKE_SOURCE_DIR}/helpers-keyfile.c"
22)30)
2331
24add_library(upstart-launcher SHARED ${LAUNCHER_SOURCES})32add_library(upstart-launcher SHARED ${LAUNCHER_SOURCES})
@@ -34,6 +42,7 @@
34 ${GOBJECT2_LIBRARIES}42 ${GOBJECT2_LIBRARIES}
35 ${LIBUPSTART_LIBRARIES}43 ${LIBUPSTART_LIBRARIES}
36 ${GIO2_LIBRARIES}44 ${GIO2_LIBRARIES}
45 ${LTTNG_LIBRARIES}
37 ${JSONGLIB_LIBRARIES}46 ${JSONGLIB_LIBRARIES}
38 -Wl,--no-undefined47 -Wl,--no-undefined
39)48)
@@ -63,3 +72,26 @@
63 DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"72 DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
64)73)
6574
75##########################
76# Introspection
77##########################
78
79include(UseGObjectIntrospection)
80
81set(INTROSPECTION_GIRS)
82set(_introspection_files ${LAUNCHER_HEADERS})
83set(UpstartAppLaunch_2_gir "upstart-app-launch")
84set(UpstartAppLaunch_2_gir_INCLUDES GObject-2.0)
85
86gir_get_cflags(_cflags)
87set(UpstartAppLaunch_2_gir_CFLAGS ${c_flags})
88set(UpstartAppLaunch_2_gir_LIBS upstart-app-launch)
89
90list_make_absolute(_abs_introspection_files _introspection_files "${CMAKE_CURRENT_SOURCE_DIR}/")
91set(UpstartAppLaunch_2_gir_FILES ${_abs_introspection_files})
92set(UpstartAppLaunch_2_gir_SCANNERFLAGS --c-include "upstart-app-launch.h")
93set(UpstartAppLaunch_2_gir_EXPORT_PACKAGES "upstart-app-launch-${API_VERSION}")
94
95list(APPEND INTROSPECTION_GIRS UpstartAppLaunch-2.gir)
96gir_add_introspections(INTROSPECTION_GIRS)
97
6698
=== renamed file 'second-exec-core.c' => 'libupstart-app-launch/second-exec-core.c'
--- second-exec-core.c 2013-12-06 10:38:35 +0000
+++ libupstart-app-launch/second-exec-core.c 2014-02-11 03:28:22 +0000
@@ -23,46 +23,49 @@
23#include "libupstart-app-launch/upstart-app-launch.h"23#include "libupstart-app-launch/upstart-app-launch.h"
24#include "helpers.h"24#include "helpers.h"
25#include "second-exec-core.h"25#include "second-exec-core.h"
26#include "second-exec-trace.h"26#include "upstart-app-launch-trace.h"
2727
28/* Globals */28typedef struct {
29GPid app_pid = 0;29 GDBusConnection * bus;
30GMainLoop * mainloop = NULL;30 gchar * appid;
31guint connections_open = 0;31 gchar * input_uris;
32const gchar * appid = NULL;32 GPid app_pid;
33const gchar * input_uris = NULL;33 guint connections_open;
34GVariant * app_data = NULL;34 GVariant * app_data;
35gchar * dbus_path = NULL;35 gchar * dbus_path;
36guint64 unity_starttime = 0;36 guint64 unity_starttime;
37guint timer = 0;37 guint timer;
38} second_exec_t;
39
40static void second_exec_complete (second_exec_t * data);
3841
39/* Unity didn't respond in time, continue on */42/* Unity didn't respond in time, continue on */
40static gboolean43static gboolean
41timer_cb (gpointer user_data)44timer_cb (gpointer user_data)
42{45{
43 tracepoint(upstart_app_launch, second_exec_resume_timeout);46 tracepoint(upstart_app_launch, second_exec_resume_timeout, ((second_exec_t *)user_data)->appid);
44 g_warning("Unity didn't respond in 500ms to resume the app");47 g_warning("Unity didn't respond in 500ms to resume the app");
45 g_main_loop_quit(mainloop);48 second_exec_complete(user_data);
46 return G_SOURCE_REMOVE;49 return G_SOURCE_REMOVE;
47}50}
4851
49/* Lower the connection count and process if it gets to zero */52/* Lower the connection count and process if it gets to zero */
50static void53static void
51connection_count_dec (void)54connection_count_dec (second_exec_t * data)
52{55{
53 tracepoint(upstart_app_launch, second_exec_connection_complete);56 tracepoint(upstart_app_launch, second_exec_connection_complete, data->appid);
54 connections_open--;57 data->connections_open--;
55 if (connections_open == 0) {58 if (data->connections_open == 0) {
56 g_debug("Finished finding connections");59 g_debug("Finished finding connections");
57 /* Check time here, either we've already heard from60 /* Check time here, either we've already heard from
58 Unity and we should send the data to the app (quit) or61 Unity and we should send the data to the app (quit) or
59 we should wait some more */62 we should wait some more */
60 guint64 timespent = g_get_monotonic_time() - unity_starttime;63 guint64 timespent = g_get_monotonic_time() - data->unity_starttime;
61 if (timespent > 500 /* ms */ * 1000 /* ms to us */) {64 if (timespent > 500 /* ms */ * 1000 /* ms to us */) {
62 g_main_loop_quit(mainloop);65 second_exec_complete(data);
63 } else {66 } else {
64 g_debug("Timer Set");67 g_debug("Timer Set");
65 timer = g_timeout_add(500 - (timespent / 1000), timer_cb, NULL);68 data->timer = g_timeout_add(500 - (timespent / 1000), timer_cb, data);
66 }69 }
67 }70 }
68 return;71 return;
@@ -73,18 +76,20 @@
73static void76static void
74unity_resume_cb (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)77unity_resume_cb (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
75{78{
79 second_exec_t * data = (second_exec_t *)user_data;
76 g_debug("Unity Completed Resume");80 g_debug("Unity Completed Resume");
77 tracepoint(upstart_app_launch, second_exec_resume_complete);81 tracepoint(upstart_app_launch, second_exec_resume_complete, data->appid);
7882
79 if (timer != 0) {83 if (data->timer != 0) {
80 g_source_remove(timer);84 g_source_remove(data->timer);
85 data->timer = 0;
81 }86 }
8287
83 if (connections_open == 0) {88 if (data->connections_open == 0) {
84 g_main_loop_quit(mainloop);89 second_exec_complete(data);
85 } else {90 } else {
86 /* Make it look like we started *forever* ago */91 /* Make it look like we started *forever* ago */
87 unity_starttime = 0;92 data->unity_starttime = 0;
88 }93 }
8994
90 return;95 return;
@@ -92,9 +97,9 @@
9297
93/* Turn the input string into something we can send to apps */98/* Turn the input string into something we can send to apps */
94static void99static void
95parse_uris (void)100parse_uris (second_exec_t * data)
96{101{
97 if (app_data != NULL) {102 if (data->app_data != NULL) {
98 /* Already done */103 /* Already done */
99 return;104 return;
100 }105 }
@@ -103,11 +108,11 @@
103 gchar ** uri_split = NULL;108 gchar ** uri_split = NULL;
104 GError * error = NULL;109 GError * error = NULL;
105110
106 g_shell_parse_argv(input_uris, NULL, &uri_split, &error);111 g_shell_parse_argv(data->input_uris, NULL, &uri_split, &error);
107112
108 if (uri_split == NULL || uri_split[0] == NULL || error != NULL) {113 if (uri_split == NULL || uri_split[0] == NULL || error != NULL) {
109 if (error != NULL) {114 if (error != NULL) {
110 g_warning("Unable to parse URLs '%s': %s", input_uris, error->message);115 g_warning("Unable to parse URLs '%s': %s", data->input_uris, error->message);
111 g_error_free(error);116 g_error_free(error);
112 }117 }
113118
@@ -136,8 +141,8 @@
136 g_variant_builder_add_value(&tuple, uris);141 g_variant_builder_add_value(&tuple, uris);
137 g_variant_builder_add_value(&tuple, platform);142 g_variant_builder_add_value(&tuple, platform);
138143
139 app_data = g_variant_builder_end(&tuple);144 data->app_data = g_variant_builder_end(&tuple);
140 g_variant_ref_sink(app_data);145 g_variant_ref_sink(data->app_data);
141146
142 return;147 return;
143}148}
@@ -149,14 +154,29 @@
149 http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus 154 http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus
150*/155*/
151static void156static void
152app_id_to_dbus_path (void)157app_id_to_dbus_path (second_exec_t * data)
153{158{
154 if (dbus_path != NULL) {159 if (data->dbus_path != NULL) {
155 return;160 return;
156 }161 }
157162
158 dbus_path = nih_dbus_path(NULL, "", appid, NULL);163 GString * str = g_string_sized_new(strlen(data->appid) + 2); /* base case, we just need a / and a null */
159 g_debug("DBus Path: %s", dbus_path);164 g_string_append_c(str, '/');
165
166 int i;
167 for (i = 0; data->appid[i] != '\0'; i++) {
168 if ((data->appid[i] >= 'a' && data->appid[i] <= 'z') ||
169 (data->appid[i] >= 'A' && data->appid[i] <= 'Z') ||
170 (data->appid[i] >= '0' && data->appid[i] <= '9' && i != 0)) {
171 g_string_append_c(str, data->appid[i]);
172 continue;
173 }
174
175 g_string_append_printf(str, "_%2x", data->appid[i]);
176 }
177
178 data->dbus_path = g_string_free(str, FALSE);
179 g_debug("DBus Path: %s", data->dbus_path);
160180
161 return;181 return;
162}182}
@@ -167,68 +187,76 @@
167{187{
168 GError * error = NULL;188 GError * error = NULL;
169189
170 tracepoint(upstart_app_launch, second_exec_app_contacted);190 tracepoint(upstart_app_launch, second_exec_app_contacted, ((second_exec_t *)user_data)->appid);
171191
172 g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);192 g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
173193
174 if (error != NULL) {194 if (error != NULL) {
175 tracepoint(upstart_app_launch, second_exec_app_error);195 tracepoint(upstart_app_launch, second_exec_app_error, ((second_exec_t *)user_data)->appid);
176 /* Mostly just to free the error, but printing for debugging */196 /* Mostly just to free the error, but printing for debugging */
177 g_debug("Unable to send Open: %s", error->message);197 g_debug("Unable to send Open: %s", error->message);
178 g_error_free(error);198 g_error_free(error);
179 }199 }
180200
181 connection_count_dec();201 connection_count_dec(user_data);
182 return;202 return;
183}203}
184204
185/* Sends the Open message to the connection with the URIs we were given */205/* Sends the Open message to the connection with the URIs we were given */
186static void206static void
187contact_app (GDBusConnection * bus, const gchar * dbus_name)207contact_app (GDBusConnection * bus, const gchar * dbus_name, second_exec_t * data)
188{208{
189 tracepoint(upstart_app_launch, second_exec_contact_app);209 tracepoint(upstart_app_launch, second_exec_contact_app, data->appid, dbus_name);
190210
191 parse_uris();211 parse_uris(data);
192 app_id_to_dbus_path();212 app_id_to_dbus_path(data);
193213
194 /* Using the FD.o Application interface */214 /* Using the FD.o Application interface */
195 g_dbus_connection_call(bus,215 g_dbus_connection_call(bus,
196 dbus_name,216 dbus_name,
197 dbus_path,217 data->dbus_path,
198 "org.freedesktop.Application",218 "org.freedesktop.Application",
199 "Open",219 "Open",
200 app_data,220 data->app_data,
201 NULL,221 NULL,
202 G_DBUS_CALL_FLAGS_NONE,222 G_DBUS_CALL_FLAGS_NONE,
203 -1,223 -1,
204 NULL,224 NULL,
205 send_open_cb, NULL);225 send_open_cb, data);
206226
207 g_debug("Sending Open request to: %s", dbus_name);227 g_debug("Sending Open request to: %s", dbus_name);
208228
209 return;229 return;
210}230}
211231
232typedef struct {
233 gchar * name;
234 second_exec_t * data;
235} get_pid_t;
236
212/* Gets the PID for a connection, and if it matches the one we're looking237/* Gets the PID for a connection, and if it matches the one we're looking
213 for then it tries to send a message to that connection */238 for then it tries to send a message to that connection */
214static void239static void
215get_pid_cb (GObject * object, GAsyncResult * res, gpointer user_data)240get_pid_cb (GObject * object, GAsyncResult * res, gpointer user_data)
216{241{
217 gchar * dbus_name = (gchar *)user_data;242 get_pid_t * data = (get_pid_t *)user_data;
218 GError * error = NULL;243 GError * error = NULL;
219 GVariant * vpid = NULL;244 GVariant * vpid = NULL;
220245
221 tracepoint(upstart_app_launch, second_exec_got_pid);246 tracepoint(upstart_app_launch, second_exec_got_pid, data->data->appid, data->name);
222247
223 vpid = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);248 vpid = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
224249
225 if (error != NULL) {250 if (error != NULL) {
226 g_warning("Unable to query PID for dbus name '%s': %s", dbus_name, error->message);251 g_warning("Unable to query PID for dbus name '%s': %s", data->name, error->message);
227 g_error_free(error);252 g_error_free(error);
228 g_free(dbus_name);
229253
230 /* Lowering the connection count, this one is terminal, even if in error */254 /* Lowering the connection count, this one is terminal, even if in error */
231 connection_count_dec();255 connection_count_dec(data->data);
256
257 g_free(data->name);
258 g_free(data);
259
232 return;260 return;
233 }261 }
234262
@@ -236,22 +264,23 @@
236 g_variant_get(vpid, "(u)", &pid);264 g_variant_get(vpid, "(u)", &pid);
237 g_variant_unref(vpid);265 g_variant_unref(vpid);
238266
239 if (pid == app_pid) {267 if (pid == data->data->app_pid) {
240 /* Trying to send a message to the connection */268 /* Trying to send a message to the connection */
241 contact_app(G_DBUS_CONNECTION(object), dbus_name);269 contact_app(G_DBUS_CONNECTION(object), data->name, data->data);
242 } else {270 } else {
243 /* See if we can quit now */271 /* See if we can quit now */
244 connection_count_dec();272 connection_count_dec(data->data);
245 }273 }
246274
247 g_free(dbus_name);275 g_free(data->name);
276 g_free(data);
248277
249 return;278 return;
250}279}
251280
252/* Starts to look for the PID and the connections for that PID */281/* Starts to look for the PID and the connections for that PID */
253void282void
254find_appid_pid (GDBusConnection * session)283find_appid_pid (GDBusConnection * session, second_exec_t * data)
255{284{
256 GError * error = NULL;285 GError * error = NULL;
257286
@@ -276,19 +305,21 @@
276 return;305 return;
277 }306 }
278307
279 tracepoint(upstart_app_launch, second_exec_got_dbus_names);308 g_debug("Got bus names");
309 tracepoint(upstart_app_launch, second_exec_got_dbus_names, data->appid);
280310
281 /* Next figure out what we're looking for (and if there is something to look for) */311 /* Next figure out what we're looking for (and if there is something to look for) */
282 /* NOTE: We're getting the PID *after* the list of connections so312 /* NOTE: We're getting the PID *after* the list of connections so
283 that some new process can't come in, be the same PID as it's313 that some new process can't come in, be the same PID as it's
284 connection will not be in teh list we just got. */314 connection will not be in teh list we just got. */
285 app_pid = upstart_app_launch_get_primary_pid(appid);315 data->app_pid = upstart_app_launch_get_primary_pid(data->appid);
286 if (app_pid == 0) {316 if (data->app_pid == 0) {
287 g_warning("Unable to find pid for app id '%s'", appid);317 g_warning("Unable to find pid for app id '%s'", data->appid);
288 return;318 return;
289 }319 }
290320
291 tracepoint(upstart_app_launch, second_exec_got_primary_pid);321 g_debug("Primary PID: %d", data->app_pid);
322 tracepoint(upstart_app_launch, second_exec_got_primary_pid, data->appid);
292323
293 /* Get the names */324 /* Get the names */
294 GVariant * names = g_variant_get_child_value(listnames, 0);325 GVariant * names = g_variant_get_child_value(listnames, 0);
@@ -301,8 +332,12 @@
301 if (!g_dbus_is_unique_name(name)) {332 if (!g_dbus_is_unique_name(name)) {
302 continue;333 continue;
303 }334 }
335
336 get_pid_t * pid_data = g_new0(get_pid_t, 1);
337 pid_data->data = data;
338 pid_data->name = g_strdup(name);
304339
305 tracepoint(upstart_app_launch, second_exec_request_pid);340 tracepoint(upstart_app_launch, second_exec_request_pid, data->appid, pid_data->name);
306341
307 /* Get the PIDs */342 /* Get the PIDs */
308 g_dbus_connection_call(session,343 g_dbus_connection_call(session,
@@ -315,9 +350,9 @@
315 G_DBUS_CALL_FLAGS_NONE,350 G_DBUS_CALL_FLAGS_NONE,
316 -1,351 -1,
317 NULL,352 NULL,
318 get_pid_cb, g_strdup(name));353 get_pid_cb, pid_data);
319354
320 connections_open++;355 data->connections_open++;
321 }356 }
322357
323 g_variant_unref(names);358 g_variant_unref(names);
@@ -329,10 +364,7 @@
329gboolean364gboolean
330second_exec (const gchar * app_id, const gchar * appuris)365second_exec (const gchar * app_id, const gchar * appuris)
331{366{
332 appid = app_id;367 tracepoint(upstart_app_launch, second_exec_start, app_id, appuris);
333 input_uris = appuris;
334
335 tracepoint(upstart_app_launch, second_exec_start);
336368
337 /* DBus tell us! */369 /* DBus tell us! */
338 GError * error = NULL;370 GError * error = NULL;
@@ -343,8 +375,11 @@
343 return FALSE;375 return FALSE;
344 }376 }
345377
346 /* Allocate main loop */378 /* Setup our continuation data */
347 mainloop = g_main_loop_new(NULL, FALSE);379 second_exec_t * data = g_new0(second_exec_t, 1);
380 data->appid = g_strdup(app_id);
381 data->input_uris = g_strdup(appuris);
382 data->bus = session;
348383
349 /* Set up listening for the unfrozen signal from Unity */384 /* Set up listening for the unfrozen signal from Unity */
350 g_dbus_connection_signal_subscribe(session,385 g_dbus_connection_signal_subscribe(session,
@@ -352,12 +387,13 @@
352 "com.canonical.UpstartAppLaunch", /* interface */387 "com.canonical.UpstartAppLaunch", /* interface */
353 "UnityResumeResponse", /* signal */388 "UnityResumeResponse", /* signal */
354 "/", /* path */389 "/", /* path */
355 appid, /* arg0 */390 app_id, /* arg0 */
356 G_DBUS_SIGNAL_FLAGS_NONE,391 G_DBUS_SIGNAL_FLAGS_NONE,
357 unity_resume_cb, mainloop,392 unity_resume_cb, data,
358 NULL); /* user data destroy */393 NULL); /* user data destroy */
359394
360 tracepoint(upstart_app_launch, second_exec_emit_resume);395 g_debug("Sending resume request");
396 tracepoint(upstart_app_launch, second_exec_emit_resume, app_id);
361397
362 /* Send unfreeze to to Unity */398 /* Send unfreeze to to Unity */
363 g_dbus_connection_emit_signal(session,399 g_dbus_connection_emit_signal(session,
@@ -365,43 +401,49 @@
365 "/", /* path */401 "/", /* path */
366 "com.canonical.UpstartAppLaunch", /* interface */402 "com.canonical.UpstartAppLaunch", /* interface */
367 "UnityResumeRequest", /* signal */403 "UnityResumeRequest", /* signal */
368 g_variant_new("(s)", appid),404 g_variant_new("(s)", app_id),
369 &error);405 &error);
370406
371 /* Now we start a race, we try to get to the point of knowing who407 /* Now we start a race, we try to get to the point of knowing who
372 to send things to, and Unity is unfrezing it. When both are408 to send things to, and Unity is unfrezing it. When both are
373 done we can send something to the app */409 done we can send something to the app */
374 unity_starttime = g_get_monotonic_time();410 data->unity_starttime = g_get_monotonic_time();
375411
376 if (error != NULL) {412 if (error != NULL) {
377 /* On error let's not wait for Unity */413 /* On error let's not wait for Unity */
378 g_warning("Unable to signal Unity: %s", error->message);414 g_warning("Unable to signal Unity: %s", error->message);
379 g_error_free(error);415 g_error_free(error);
380 error = NULL;416 error = NULL;
381 unity_starttime = 0;417 data->unity_starttime = 0;
382 }418 }
383419
384 /* If we've got something to give out, start looking for how */420 /* If we've got something to give out, start looking for how */
385 if (input_uris != NULL) {421 if (data->input_uris != NULL) {
386 find_appid_pid(session);422 find_appid_pid(session, data);
387 }423 }
388424
389 /* Loop and wait for everything to align */425 /* Loop and wait for everything to align */
390 if (connections_open > 0 || unity_starttime > 0) {426 if (data->connections_open == 0 && data->unity_starttime == 0) {
391 g_main_loop_run(mainloop);427 second_exec_complete(data);
392 }428 }
393 g_debug("Finishing main loop");429
394430 return TRUE;
395 tracepoint(upstart_app_launch, second_exec_emit_focus);431}
432
433static void
434second_exec_complete (second_exec_t * data)
435{
436 GError * error = NULL;
437 tracepoint(upstart_app_launch, second_exec_emit_focus, data->appid);
396438
397 /* Now that we're done sending the info to the app, we can ask439 /* Now that we're done sending the info to the app, we can ask
398 Unity to focus the application. */440 Unity to focus the application. */
399 g_dbus_connection_emit_signal(session,441 g_dbus_connection_emit_signal(data->bus,
400 NULL, /* destination */442 NULL, /* destination */
401 "/", /* path */443 "/", /* path */
402 "com.canonical.UpstartAppLaunch", /* interface */444 "com.canonical.UpstartAppLaunch", /* interface */
403 "UnityFocusRequest", /* signal */445 "UnityFocusRequest", /* signal */
404 g_variant_new("(s)", appid),446 g_variant_new("(s)", data->appid),
405 &error);447 &error);
406448
407 if (error != NULL) {449 if (error != NULL) {
@@ -411,23 +453,23 @@
411 }453 }
412454
413 /* Make sure the signal hits the bus */455 /* Make sure the signal hits the bus */
414 g_dbus_connection_flush_sync(session, NULL, NULL);456 g_dbus_connection_flush_sync(data->bus, NULL, &error);
457 if (error != NULL) {
458 g_warning("Unable to flush session bus: %s", error->message);
459 g_error_free(error);
460 error = NULL;
461 }
462
463 tracepoint(upstart_app_launch, second_exec_finish, data->appid);
415464
416 /* Clean up */465 /* Clean up */
417 if (app_data != NULL) {466 g_object_unref(data->bus);
418 g_variant_unref(app_data);467 if (data->app_data != NULL)
419 app_data = NULL;468 g_variant_unref(data->app_data);
420 }469 g_free(data->appid);
421470 g_free(data->input_uris);
422 g_main_loop_unref(mainloop);471 g_free(data->dbus_path);
423 g_object_unref(session);472 g_free(data);
424473
425 if (dbus_path != NULL) {474 return;
426 nih_free(dbus_path);
427 dbus_path = NULL;
428 }
429
430 tracepoint(upstart_app_launch, second_exec_finish);
431
432 return TRUE;
433}475}
434476
=== renamed file 'second-exec-core.h' => 'libupstart-app-launch/second-exec-core.h'
=== added file 'libupstart-app-launch/upstart-app-launch-trace.tp'
--- libupstart-app-launch/upstart-app-launch-trace.tp 1970-01-01 00:00:00 +0000
+++ libupstart-app-launch/upstart-app-launch-trace.tp 2014-02-11 03:28:22 +0000
@@ -0,0 +1,170 @@
1
2/*******************************
3 LibUAL start function
4 *******************************/
5TRACEPOINT_EVENT(upstart_app_launch, libual_start,
6 TP_ARGS(const char *, appid),
7 TP_FIELDS(
8 ctf_string(appid, appid)
9 )
10)
11TRACEPOINT_EVENT(upstart_app_launch, libual_determine_type,
12 TP_ARGS(const char *, appid, const char *, type),
13 TP_FIELDS(
14 ctf_string(appid, appid)
15 ctf_string(type, type)
16 )
17)
18TRACEPOINT_EVENT(upstart_app_launch, libual_job_path_determined,
19 TP_ARGS(const char *, appid, const char *, job_path),
20 TP_FIELDS(
21 ctf_string(appid, appid)
22 ctf_string(job_path, job_path)
23 )
24)
25TRACEPOINT_EVENT(upstart_app_launch, libual_start_message_sent,
26 TP_ARGS(const char *, appid),
27 TP_FIELDS(
28 ctf_string(appid, appid)
29 )
30)
31TRACEPOINT_EVENT(upstart_app_launch, libual_start_message_callback,
32 TP_ARGS(const char *, appid),
33 TP_FIELDS(
34 ctf_string(appid, appid)
35 )
36)
37
38/*******************************
39 LibUAL observers
40 *******************************/
41
42TRACEPOINT_EVENT(upstart_app_launch, observer_start,
43 TP_ARGS(const char *, type),
44 TP_FIELDS(
45 ctf_string(type, type)
46 )
47)
48TRACEPOINT_EVENT(upstart_app_launch, observer_finish,
49 TP_ARGS(const char *, type),
50 TP_FIELDS(
51 ctf_string(type, type)
52 )
53)
54
55
56/*******************************
57 Second Exec tracking
58 *******************************/
59TRACEPOINT_EVENT(upstart_app_launch, second_exec_start,
60 TP_ARGS(const char *, appid, const char *, appuris),
61 TP_FIELDS(
62 ctf_string(appid, appid)
63 ctf_string(appuris, appuris)
64 )
65)
66TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_resume,
67 TP_ARGS(const char *, appid),
68 TP_FIELDS(
69 ctf_string(appid, appid)
70 )
71)
72TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_complete,
73 TP_ARGS(const char *, appid),
74 TP_FIELDS(
75 ctf_string(appid, appid)
76 )
77)
78TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_timeout,
79 TP_ARGS(const char *, appid),
80 TP_FIELDS(
81 ctf_string(appid, appid)
82 )
83)
84TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_focus,
85 TP_ARGS(const char *, appid),
86 TP_FIELDS(
87 ctf_string(appid, appid)
88 )
89)
90TRACEPOINT_EVENT(upstart_app_launch, second_exec_finish,
91 TP_ARGS(const char *, appid),
92 TP_FIELDS(
93 ctf_string(appid, appid)
94 )
95)
96TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_dbus_names,
97 TP_ARGS(const char *, appid),
98 TP_FIELDS(
99 ctf_string(appid, appid)
100 )
101)
102TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_primary_pid,
103 TP_ARGS(const char *, appid),
104 TP_FIELDS(
105 ctf_string(appid, appid)
106 )
107)
108TRACEPOINT_EVENT(upstart_app_launch, second_exec_request_pid,
109 TP_ARGS(const char *, appid, const char *, dbus_name),
110 TP_FIELDS(
111 ctf_string(appid, appid)
112 ctf_string(dbus_name, dbus_name)
113 )
114)
115TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_pid,
116 TP_ARGS(const char *, appid, const char *, dbus_name),
117 TP_FIELDS(
118 ctf_string(appid, appid)
119 ctf_string(dbus_name, dbus_name)
120 )
121)
122TRACEPOINT_EVENT(upstart_app_launch, second_exec_contact_app,
123 TP_ARGS(const char *, appid, const char *, dbus_name),
124 TP_FIELDS(
125 ctf_string(appid, appid)
126 ctf_string(dbus_name, dbus_name)
127 )
128)
129TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_contacted,
130 TP_ARGS(const char *, appid),
131 TP_FIELDS(
132 ctf_string(appid, appid)
133 )
134)
135TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_error,
136 TP_ARGS(const char *, appid),
137 TP_FIELDS(
138 ctf_string(appid, appid)
139 )
140)
141TRACEPOINT_EVENT(upstart_app_launch, second_exec_connection_complete,
142 TP_ARGS(const char *, appid),
143 TP_FIELDS(
144 ctf_string(appid, appid)
145 )
146)
147
148/*******************************
149 Desktop File Single Instance
150 *******************************/
151TRACEPOINT_EVENT(upstart_app_launch, desktop_single_start,
152 TP_ARGS(const char *, appid),
153 TP_FIELDS(
154 ctf_string(appid, appid)
155 )
156)
157TRACEPOINT_EVENT(upstart_app_launch, desktop_single_found,
158 TP_ARGS(const char *, appid),
159 TP_FIELDS(
160 ctf_string(appid, appid)
161 )
162)
163TRACEPOINT_EVENT(upstart_app_launch, desktop_single_finished,
164 TP_ARGS(const char *, appid, const char *, apptype),
165 TP_FIELDS(
166 ctf_string(appid, appid)
167 ctf_string(apptype, apptype)
168 )
169)
170
0171
=== modified file 'libupstart-app-launch/upstart-app-launch.c'
--- libupstart-app-launch/upstart-app-launch.c 2014-01-29 02:19:27 +0000
+++ libupstart-app-launch/upstart-app-launch.c 2014-02-11 03:28:22 +0000
@@ -20,53 +20,16 @@
20#include "upstart-app-launch.h"20#include "upstart-app-launch.h"
21#include <json-glib/json-glib.h>21#include <json-glib/json-glib.h>
22#include <upstart.h>22#include <upstart.h>
23#include <nih/alloc.h>
24#include <nih/error.h>
25#include <gio/gio.h>23#include <gio/gio.h>
26#include <string.h>24#include <string.h>
2725
28static void apps_for_job (NihDBusProxy * upstart, const gchar * name, GArray * apps, gboolean truncate_legacy);26#include "upstart-app-launch-trace.h"
27#include "second-exec-core.h"
28#include "../helpers.h"
29
30static void apps_for_job (GDBusConnection * con, const gchar * name, GArray * apps, gboolean truncate_legacy);
29static void free_helper (gpointer value);31static void free_helper (gpointer value);
3032
31static NihDBusProxy *
32nih_proxy_create (void)
33{
34 NihDBusProxy * upstart;
35 DBusConnection * conn;
36 DBusError error;
37 const gchar * bus_name = NULL;
38
39 dbus_error_init(&error);
40
41 conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
42 bus_name = "com.ubuntu.Upstart";
43
44 if (conn == NULL) {
45 g_warning("Unable to connect to the Upstart Session: %s", error.message);
46 dbus_error_free(&error);
47 return NULL;
48 }
49
50 dbus_error_free(&error);
51
52 upstart = nih_dbus_proxy_new(NULL, conn,
53 bus_name,
54 DBUS_PATH_UPSTART,
55 NULL, NULL);
56
57 if (upstart == NULL) {
58 g_warning("Unable to build proxy to Upstart");
59 dbus_connection_unref(conn);
60 return NULL;
61 }
62
63 dbus_connection_unref(conn);
64
65 upstart->auto_start = FALSE;
66
67 return upstart;
68}
69
70/* Function to take the urls and escape them so that they can be33/* Function to take the urls and escape them so that they can be
71 parsed on the other side correctly. */34 parsed on the other side correctly. */
72static gchar *35static gchar *
@@ -87,83 +50,261 @@
87 return urisjoin;50 return urisjoin;
88}51}
8952
53typedef struct {
54 gchar * appid;
55 gchar * uris;
56} app_start_t;
57
58static void
59application_start_cb (GObject * obj, GAsyncResult * res, gpointer user_data)
60{
61 app_start_t * data = (app_start_t *)user_data;
62 GError * error = NULL;
63 GVariant * result = NULL;
64
65 tracepoint(upstart_app_launch, libual_start_message_callback, data->appid);
66 g_debug("Started Message Callback: %s", data->appid);
67
68 result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
69
70 if (result != NULL)
71 g_variant_unref(result);
72
73 if (error != NULL) {
74 if (g_dbus_error_is_remote_error(error)) {
75 gchar * remote_error = g_dbus_error_get_remote_error(error);
76 g_debug("Remote error: %s", remote_error);
77 if (g_strcmp0(remote_error, "com.ubuntu.Upstart0_6.Error.AlreadyStarted") == 0) {
78 second_exec(data->appid, data->uris);
79 }
80
81 g_free(remote_error);
82 } else {
83 g_warning("Unable to emit event to start application: %s", error->message);
84 }
85 g_error_free(error);
86 }
87
88 g_free(data->appid);
89 g_free(data->uris);
90 g_free(data);
91}
92
93/* Get the path of the job from Upstart, if we've got it already, we'll just
94 use the cache of the value */
95static const gchar *
96get_jobpath (GDBusConnection * con, const gchar * jobname)
97{
98 gchar * cachepath = g_strdup_printf("upstart-app-lauch-job-path-cache-%s", jobname);
99 gpointer cachedata = g_object_get_data(G_OBJECT(con), cachepath);
100
101 if (cachedata != NULL) {
102 g_free(cachepath);
103 return cachedata;
104 }
105
106 GError * error = NULL;
107 GVariant * job_path_variant = g_dbus_connection_call_sync(con,
108 DBUS_SERVICE_UPSTART,
109 DBUS_PATH_UPSTART,
110 DBUS_INTERFACE_UPSTART,
111 "GetJobByName",
112 g_variant_new("(s)", jobname),
113 G_VARIANT_TYPE("(o)"),
114 G_DBUS_CALL_FLAGS_NONE,
115 -1, /* timeout: default */
116 NULL, /* cancelable */
117 &error);
118
119 if (error != NULL) {
120 g_warning("Unable to find job '%s': %s", jobname, error->message);
121 g_error_free(error);
122 g_free(cachepath);
123 return NULL;
124 }
125
126 gchar * job_path = NULL;
127 g_variant_get(job_path_variant, "(o)", &job_path);
128 g_variant_unref(job_path_variant);
129
130 g_object_set_data_full(G_OBJECT(con), cachepath, job_path, g_free);
131 g_free(cachepath);
132
133 return job_path;
134}
135
136/* Check to see if a legacy app wants us to manage whether they're
137 single instance or not */
138static gboolean
139legacy_single_instance (const gchar * appid)
140{
141 tracepoint(upstart_app_launch, desktop_single_start, appid);
142
143 GKeyFile * keyfile = keyfile_for_appid(appid, NULL);
144
145 if (keyfile == NULL) {
146 g_error("Unable to find keyfile for application '%s'", appid);
147 return FALSE;
148 }
149
150 tracepoint(upstart_app_launch, desktop_single_found, appid);
151
152 gboolean singleinstance = FALSE;
153
154 if (g_key_file_has_key(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", NULL)) {
155 GError * error = NULL;
156
157 singleinstance = g_key_file_get_boolean(keyfile, "Desktop Entry", "X-Ubuntu-Single-Instance", &error);
158
159 if (error != NULL) {
160 g_warning("Unable to get single instance key for app '%s': %s", appid, error->message);
161 g_error_free(error);
162 /* Ensure that if we got an error, we assume standard case */
163 singleinstance = FALSE;
164 }
165 }
166
167 g_key_file_free(keyfile);
168
169 tracepoint(upstart_app_launch, desktop_single_finished, appid, singleinstance ? "single" : "unmanaged");
170
171 return singleinstance;
172}
173
90gboolean174gboolean
91upstart_app_launch_start_application (const gchar * appid, const gchar * const * uris)175upstart_app_launch_start_application (const gchar * appid, const gchar * const * uris)
92{176{
93 NihDBusProxy * proxy = NULL;177 g_return_val_if_fail(appid != NULL, FALSE);
94178
95 proxy = nih_proxy_create();179 tracepoint(upstart_app_launch, libual_start, appid);
96 if (proxy == NULL) {180
181 GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
182 g_return_val_if_fail(con != NULL, FALSE);
183
184 /* Determine whether it's a click package by looking for the symlink
185 that is created by the desktop hook */
186 gchar * appiddesktop = g_strdup_printf("%s.desktop", appid);
187 gchar * click_link = NULL;
188 const gchar * link_farm_dir = g_getenv("UPSTART_APP_LAUNCH_LINK_FARM");
189 if (G_LIKELY(link_farm_dir == NULL)) {
190 click_link = g_build_filename(g_get_home_dir(), ".cache", "upstart-app-launch", "desktop", appiddesktop, NULL);
191 } else {
192 click_link = g_build_filename(link_farm_dir, appiddesktop, NULL);
193 }
194 g_free(appiddesktop);
195 gboolean click = g_file_test(click_link, G_FILE_TEST_EXISTS);
196 g_free(click_link);
197
198 tracepoint(upstart_app_launch, libual_determine_type, appid, click ? "click" : "legacy");
199
200 /* Figure out the DBus path for the job */
201 const gchar * jobpath = NULL;
202 if (click) {
203 jobpath = get_jobpath(con, "application-click");
204 } else {
205 jobpath = get_jobpath(con, "application-legacy");
206 }
207
208 if (jobpath == NULL)
97 return FALSE;209 return FALSE;
98 }210
99211 tracepoint(upstart_app_launch, libual_job_path_determined, appid, jobpath);
100 gchar * env_appid = g_strdup_printf("APP_ID=%s", appid);212
101 gchar * env_uris = NULL;213 /* Callback data */
214 app_start_t * app_start_data = g_new0(app_start_t, 1);
215 app_start_data->appid = g_strdup(appid);
216
217 /* Build up our environment */
218 GVariantBuilder builder;
219 g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
220
221 g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
222
223 g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("APP_ID=%s", appid)));
102224
103 if (uris != NULL) {225 if (uris != NULL) {
104 gchar * urisjoin = app_uris_string(uris);226 gchar * urisjoin = app_uris_string(uris);
105 env_uris = g_strdup_printf("APP_URIS=%s", urisjoin);227 gchar * urienv = g_strdup_printf("APP_URIS=%s", urisjoin);
106 g_free(urisjoin);228 app_start_data->uris = urisjoin;
107 }229 g_variant_builder_add_value(&builder, g_variant_new_take_string(urienv));
108230 }
109 gchar * env[3];231
110 env[0] = env_appid;232 if (!click) {
111 env[1] = env_uris;233 if (legacy_single_instance(appid)) {
112 env[2] = NULL;234 g_variant_builder_add_value(&builder, g_variant_new_string("INSTANCE_ID="));
113235 } else {
114 gboolean retval = TRUE;236 gchar * instanceid = g_strdup_printf("INSTANCE_ID=%" G_GUINT64_FORMAT, g_get_real_time());
115 if (upstart_emit_event_sync(NULL, proxy, "application-start", env, 0) != 0) {237 g_variant_builder_add_value(&builder, g_variant_new_take_string(instanceid));
116 g_warning("Unable to emit signal 'application-start'");238 }
117 retval = FALSE;239 }
118 }240
119241 g_variant_builder_close(&builder);
120 g_free(env_appid);242 g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
121 g_free(env_uris);243
122 nih_unref(proxy, NULL);244 /* Call the job start function */
123245 g_dbus_connection_call(con,
124 return retval;246 DBUS_SERVICE_UPSTART,
247 jobpath,
248 DBUS_INTERFACE_UPSTART_JOB,
249 "Start",
250 g_variant_builder_end(&builder),
251 NULL,
252 G_DBUS_CALL_FLAGS_NONE,
253 -1,
254 NULL, /* cancelable */
255 application_start_cb,
256 app_start_data);
257
258 tracepoint(upstart_app_launch, libual_start_message_sent, appid);
259
260 g_object_unref(con);
261
262 return TRUE;
125}263}
126264
127static void265static void
128stop_job (NihDBusProxy * upstart, const gchar * jobname, const gchar * appname, const gchar * instanceid)266stop_job (GDBusConnection * con, const gchar * jobname, const gchar * appname, const gchar * instanceid)
129{267{
130 g_debug("Stopping job %s app_id %s instance_id %s", jobname, appname, instanceid);268 g_debug("Stopping job %s app_id %s instance_id %s", jobname, appname, instanceid);
131 nih_local char * job_path = NULL;269
132 if (upstart_get_job_by_name_sync(NULL, upstart, jobname, &job_path) != 0) {270 const gchar * job_path = get_jobpath(con, jobname);
133 g_warning("Unable to find job '%s'", jobname);271 if (job_path == NULL)
134 return;272 return;
135 }273
136274 GVariantBuilder builder;
137 NihDBusProxy * job_proxy = nih_dbus_proxy_new(NULL, upstart->connection,275 g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
138 upstart->name,276 g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
139 job_path,277
140 NULL, NULL);278 g_variant_builder_add_value(&builder,
141279 g_variant_new_take_string(g_strdup_printf("APP_ID=%s", appname)));
142 if (job_proxy == NULL) {
143 g_warning("Unable to build proxy to Job '%s'", jobname);
144 return;
145 }
146
147 gchar * app = g_strdup_printf("APP_ID=%s", appname);
148 gchar * inst = NULL;
149 280
150 if (instanceid != NULL) {281 if (instanceid != NULL) {
151 inst = g_strdup_printf("INSTANCE_ID=%s", instanceid);282 g_variant_builder_add_value(&builder,
152 }283 g_variant_new_take_string(g_strdup_printf("INSTANCE_ID=%s", instanceid)));
153284 }
154 gchar * env[3] = {285
155 app,286 g_variant_builder_close(&builder);
156 inst,287 g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); /* wait */
157 NULL288
158 };289 GError * error = NULL;
159290 GVariant * stop_variant = g_dbus_connection_call_sync(con,
160 if (job_class_stop_sync(NULL, job_proxy, env, 0) != 0) {291 DBUS_SERVICE_UPSTART,
161 g_warning("Unable to stop job %s app %s instance %s", jobname, appname, instanceid);292 job_path,
162 }293 DBUS_INTERFACE_UPSTART_JOB,
163294 "Stop",
164 g_free(app);295 g_variant_builder_end(&builder),
165 g_free(inst);296 NULL,
166 nih_unref(job_proxy, NULL);297 G_DBUS_CALL_FLAGS_NONE,
298 -1, /* timeout: default */
299 NULL, /* cancelable */
300 &error);
301
302 if (error != NULL) {
303 g_warning("Unable to stop job %s app_id %s instance_id %s: %s", jobname, appname, instanceid, error->message);
304 g_error_free(error);
305 }
306
307 g_variant_unref(stop_variant);
167}308}
168309
169static void310static void
@@ -176,25 +317,24 @@
176gboolean317gboolean
177upstart_app_launch_stop_application (const gchar * appid)318upstart_app_launch_stop_application (const gchar * appid)
178{319{
320 g_return_val_if_fail(appid != NULL, FALSE);
321
322 GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
323 g_return_val_if_fail(con != NULL, FALSE);
324
179 gboolean found = FALSE;325 gboolean found = FALSE;
180 int i;326 int i;
181 NihDBusProxy * proxy = NULL;
182
183 proxy = nih_proxy_create();
184 if (proxy == NULL) {
185 return FALSE;
186 }
187327
188 GArray * apps = g_array_new(TRUE, TRUE, sizeof(gchar *));328 GArray * apps = g_array_new(TRUE, TRUE, sizeof(gchar *));
189 g_array_set_clear_func(apps, free_helper);329 g_array_set_clear_func(apps, free_helper);
190330
191 /* Look through the click jobs and see if any match. There can331 /* Look through the click jobs and see if any match. There can
192 only be one instance for each ID in the click world */332 only be one instance for each ID in the click world */
193 apps_for_job(proxy, "application-click", apps, FALSE);333 apps_for_job(con, "application-click", apps, FALSE);
194 for (i = 0; i < apps->len; i++) {334 for (i = 0; i < apps->len; i++) {
195 const gchar * array_id = g_array_index(apps, const gchar *, i);335 const gchar * array_id = g_array_index(apps, const gchar *, i);
196 if (g_strcmp0(array_id, appid) == 0) {336 if (g_strcmp0(array_id, appid) == 0) {
197 stop_job(proxy, "application-click", appid, NULL);337 stop_job(con, "application-click", appid, NULL);
198 found = TRUE;338 found = TRUE;
199 break; /* There can be only one with click */339 break; /* There can be only one with click */
200 }340 }
@@ -206,20 +346,20 @@
206 /* Look through the legacy apps. Trickier because we know that there346 /* Look through the legacy apps. Trickier because we know that there
207 can be many instances of the legacy jobs out there, so we might347 can be many instances of the legacy jobs out there, so we might
208 have to kill more than one of them. */348 have to kill more than one of them. */
209 apps_for_job(proxy, "application-legacy", apps, FALSE);349 apps_for_job(con, "application-legacy", apps, FALSE);
210 gchar * appiddash = g_strdup_printf("%s-", appid); /* Probably could go RegEx here, but let's start with just a prefix lookup */350 gchar * appiddash = g_strdup_printf("%s-", appid); /* Probably could go RegEx here, but let's start with just a prefix lookup */
211 for (i = 0; i < apps->len; i++) {351 for (i = 0; i < apps->len; i++) {
212 const gchar * array_id = g_array_index(apps, const gchar *, i);352 const gchar * array_id = g_array_index(apps, const gchar *, i);
213 if (g_str_has_prefix(array_id, appiddash)) {353 if (g_str_has_prefix(array_id, appiddash)) {
214 gchar * instanceid = g_strrstr(array_id, "-");354 gchar * instanceid = g_strrstr(array_id, "-");
215 stop_job(proxy, "application-legacy", appid, &(instanceid[1]));355 stop_job(con, "application-legacy", appid, &(instanceid[1]));
216 found = TRUE;356 found = TRUE;
217 }357 }
218 }358 }
219 g_free(appiddash);359 g_free(appiddash);
220360
221 g_array_free(apps, TRUE);361 g_array_free(apps, TRUE);
222 nih_unref(proxy, NULL);362 g_object_unref(con);
223363
224 return found;364 return found;
225}365}
@@ -255,18 +395,33 @@
255 gpointer user_data;395 gpointer user_data;
256};396};
257397
398/* The data we keep for each failed observer */
399typedef struct _failed_observer_t failed_observer_t;
400struct _failed_observer_t {
401 GDBusConnection * conn;
402 guint sighandle;
403 upstart_app_launch_app_failed_observer_t func;
404 gpointer user_data;
405};
406
258/* The lists of Observers */407/* The lists of Observers */
259static GList * starting_array = NULL;408static GList * starting_array = NULL;
260static GList * started_array = NULL;409static GList * started_array = NULL;
261static GList * stop_array = NULL;410static GList * stop_array = NULL;
262static GList * focus_array = NULL;411static GList * focus_array = NULL;
263static GList * resume_array = NULL;412static GList * resume_array = NULL;
413static GList * failed_array = NULL;
264414
265static void415static void
266observer_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)416observer_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
267{417{
268 observer_t * observer = (observer_t *)user_data;418 observer_t * observer = (observer_t *)user_data;
269419
420 const gchar * signalname = NULL;
421 g_variant_get_child(params, 0, "&s", &signalname);
422
423 tracepoint(upstart_app_launch, observer_start, signalname);
424
270 gchar * env = NULL;425 gchar * env = NULL;
271 GVariant * envs = g_variant_get_child_value(params, 1);426 GVariant * envs = g_variant_get_child_value(params, 1);
272 GVariantIter iter;427 GVariantIter iter;
@@ -300,6 +455,8 @@
300 observer->func(instance, observer->user_data);455 observer->func(instance, observer->user_data);
301 }456 }
302457
458 tracepoint(upstart_app_launch, observer_finish, signalname);
459
303 g_free(instance);460 g_free(instance);
304}461}
305462
@@ -388,10 +545,14 @@
388 observer_t * observer = (observer_t *)user_data;545 observer_t * observer = (observer_t *)user_data;
389 const gchar * appid = NULL;546 const gchar * appid = NULL;
390547
548 tracepoint(upstart_app_launch, observer_start, "focus");
549
391 if (observer->func != NULL) {550 if (observer->func != NULL) {
392 g_variant_get(params, "(&s)", &appid);551 g_variant_get(params, "(&s)", &appid);
393 observer->func(appid, observer->user_data);552 observer->func(appid, observer->user_data);
394 }553 }
554
555 tracepoint(upstart_app_launch, observer_finish, "focus");
395}556}
396557
397gboolean558gboolean
@@ -404,6 +565,8 @@
404static void565static void
405resume_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)566resume_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
406{567{
568 tracepoint(upstart_app_launch, observer_start, "resume");
569
407 focus_signal_cb(conn, sender, object, interface, signal, params, user_data);570 focus_signal_cb(conn, sender, object, interface, signal, params, user_data);
408571
409 GError * error = NULL;572 GError * error = NULL;
@@ -419,6 +582,8 @@
419 g_warning("Unable to emit response signal: %s", error->message);582 g_warning("Unable to emit response signal: %s", error->message);
420 g_error_free(error);583 g_error_free(error);
421 }584 }
585
586 tracepoint(upstart_app_launch, observer_finish, "resume");
422}587}
423588
424gboolean589gboolean
@@ -431,6 +596,8 @@
431static void596static void
432starting_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)597starting_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
433{598{
599 tracepoint(upstart_app_launch, observer_start, "starting");
600
434 focus_signal_cb(conn, sender, object, interface, signal, params, user_data);601 focus_signal_cb(conn, sender, object, interface, signal, params, user_data);
435602
436 GError * error = NULL;603 GError * error = NULL;
@@ -446,6 +613,8 @@
446 g_warning("Unable to emit response signal: %s", error->message);613 g_warning("Unable to emit response signal: %s", error->message);
447 g_error_free(error);614 g_error_free(error);
448 }615 }
616
617 tracepoint(upstart_app_launch, observer_finish, "starting");
449}618}
450619
451gboolean620gboolean
@@ -454,10 +623,63 @@
454 return add_session_generic(observer, user_data, "UnityStartingBroadcast", &starting_array, starting_signal_cb);623 return add_session_generic(observer, user_data, "UnityStartingBroadcast", &starting_array, starting_signal_cb);
455}624}
456625
626/* Handle the failed signal when it occurs, call the observer */
627static void
628failed_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
629{
630 failed_observer_t * observer = (failed_observer_t *)user_data;
631 const gchar * appid = NULL;
632 const gchar * typestr = NULL;
633
634 tracepoint(upstart_app_launch, observer_start, "failed");
635
636 if (observer->func != NULL) {
637 upstart_app_launch_app_failed_t type = UPSTART_APP_LAUNCH_APP_FAILED_CRASH;
638 g_variant_get(params, "(&s&s)", &appid, &typestr);
639
640 if (g_strcmp0("crash", typestr) == 0) {
641 type = UPSTART_APP_LAUNCH_APP_FAILED_CRASH;
642 } else if (g_strcmp0("start-failure", typestr) == 0) {
643 type = UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE;
644 } else {
645 g_warning("Application failure type '%s' unknown, reporting as a crash", typestr);
646 }
647
648 observer->func(appid, type, observer->user_data);
649 }
650
651 tracepoint(upstart_app_launch, observer_finish, "failed");
652}
653
457gboolean654gboolean
458upstart_app_launch_observer_add_app_failed (upstart_app_launch_app_failed_observer_t observer, gpointer user_data)655upstart_app_launch_observer_add_app_failed (upstart_app_launch_app_failed_observer_t observer, gpointer user_data)
459{656{
460 return FALSE;657 GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
658
659 if (conn == NULL) {
660 return FALSE;
661 }
662
663 failed_observer_t * observert = g_new0(failed_observer_t, 1);
664
665 observert->conn = conn;
666 observert->func = observer;
667 observert->user_data = user_data;
668
669 failed_array = g_list_prepend(failed_array, observert);
670
671 observert->sighandle = g_dbus_connection_signal_subscribe(conn,
672 NULL, /* sender */
673 "com.canonical.UpstartAppLaunch", /* interface */
674 "ApplicationFailed", /* signal */
675 "/", /* path */
676 NULL, /* arg0 */
677 G_DBUS_SIGNAL_FLAGS_NONE,
678 failed_signal_cb,
679 observert,
680 NULL); /* user data destroy */
681
682 return TRUE;
461}683}
462684
463static gboolean685static gboolean
@@ -520,167 +742,234 @@
520gboolean742gboolean
521upstart_app_launch_observer_delete_app_failed (upstart_app_launch_app_failed_observer_t observer, gpointer user_data)743upstart_app_launch_observer_delete_app_failed (upstart_app_launch_app_failed_observer_t observer, gpointer user_data)
522{744{
523 return FALSE;745 failed_observer_t * observert = NULL;
746 GList * look;
747
748 for (look = failed_array; look != NULL; look = g_list_next(look)) {
749 observert = (failed_observer_t *)look->data;
750
751 if (observert->func == observer && observert->user_data == user_data) {
752 break;
753 }
754 }
755
756 if (look == NULL) {
757 return FALSE;
758 }
759
760 g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);
761 g_object_unref(observert->conn);
762
763 g_free(observert);
764 failed_array = g_list_delete_link(failed_array, look);
765
766 return TRUE;
767}
768
769typedef void (*per_instance_func_t) (GDBusConnection * con, GVariant * prop_dict, gpointer user_data);
770
771static void
772foreach_job_instance (GDBusConnection * con, const gchar * jobname, per_instance_func_t func, gpointer user_data)
773{
774 const gchar * job_path = get_jobpath(con, jobname);
775 if (job_path == NULL)
776 return;
777
778 GError * error = NULL;
779 GVariant * instance_tuple = g_dbus_connection_call_sync(con,
780 DBUS_SERVICE_UPSTART,
781 job_path,
782 DBUS_INTERFACE_UPSTART_JOB,
783 "GetAllInstances",
784 NULL,
785 G_VARIANT_TYPE("(ao)"),
786 G_DBUS_CALL_FLAGS_NONE,
787 -1, /* timeout: default */
788 NULL, /* cancelable */
789 &error);
790
791 if (error != NULL) {
792 g_warning("Unable to get instances of job '%s': %s", jobname, error->message);
793 g_error_free(error);
794 return;
795 }
796
797 GVariant * instance_list = g_variant_get_child_value(instance_tuple, 0);
798 g_variant_unref(instance_tuple);
799
800 GVariantIter instance_iter;
801 g_variant_iter_init(&instance_iter, instance_list);
802 const gchar * instance_path = NULL;
803
804 while (g_variant_iter_loop(&instance_iter, "&o", &instance_path)) {
805 GVariant * props_tuple = g_dbus_connection_call_sync(con,
806 DBUS_SERVICE_UPSTART,
807 instance_path,
808 "org.freedesktop.DBus.Properties",
809 "GetAll",
810 g_variant_new("(s)", DBUS_INTERFACE_UPSTART_INSTANCE),
811 G_VARIANT_TYPE("(a{sv})"),
812 G_DBUS_CALL_FLAGS_NONE,
813 -1, /* timeout: default */
814 NULL, /* cancelable */
815 &error);
816
817 if (error != NULL) {
818 g_warning("Unable to name of instance '%s': %s", instance_path, error->message);
819 g_error_free(error);
820 error = NULL;
821 continue;
822 }
823
824 GVariant * props_dict = g_variant_get_child_value(props_tuple, 0);
825
826 func(con, props_dict, user_data);
827
828 g_variant_unref(props_dict);
829 g_variant_unref(props_tuple);
830
831 }
832
833 g_variant_unref(instance_list);
834}
835
836typedef struct {
837 GArray * apps;
838 gboolean truncate_legacy;
839 const gchar * jobname;
840} apps_for_job_t;
841
842static void
843apps_for_job_instance (GDBusConnection * con, GVariant * props_dict, gpointer user_data)
844{
845 GVariant * namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
846 if (namev == NULL) {
847 return;
848 }
849
850 apps_for_job_t * data = (apps_for_job_t *)user_data;
851 gchar * instance_name = g_variant_dup_string(namev, NULL);
852 g_variant_unref(namev);
853
854 if (data->truncate_legacy && g_strcmp0(data->jobname, "application-legacy") == 0) {
855 gchar * last_dash = g_strrstr(instance_name, "-");
856 if (last_dash != NULL) {
857 last_dash[0] = '\0';
858 }
859 }
860
861 g_array_append_val(data->apps, instance_name);
524}862}
525863
526/* Get all the instances for a given job name */864/* Get all the instances for a given job name */
527static void865static void
528apps_for_job (NihDBusProxy * upstart, const gchar * name, GArray * apps, gboolean truncate_legacy)866apps_for_job (GDBusConnection * con, const gchar * jobname, GArray * apps, gboolean truncate_legacy)
529{867{
530 nih_local char * job_path = NULL;868 apps_for_job_t data = {
531 if (upstart_get_job_by_name_sync(NULL, upstart, name, &job_path) != 0) {869 .jobname = jobname,
532 g_warning("Unable to find job '%s'", name);870 .apps = apps,
533 return;871 .truncate_legacy = truncate_legacy
534 }872 };
535873
536 nih_local NihDBusProxy * job_proxy = nih_dbus_proxy_new(NULL, upstart->connection,874 foreach_job_instance(con, jobname, apps_for_job_instance, &data);
537 upstart->name,
538 job_path,
539 NULL, NULL);
540
541 if (job_proxy == NULL) {
542 g_warning("Unable to build proxy to Job '%s'", name);
543 return;
544 }
545
546 nih_local char ** instances;
547 if (job_class_get_all_instances_sync(NULL, job_proxy, &instances) != 0) {
548 NihError * error = nih_error_get();
549 g_warning("Unable to get instances for job '%s': %s", name, error->message);
550 nih_free(error);
551 return;
552 }
553
554 int jobnum;
555 for (jobnum = 0; instances[jobnum] != NULL; jobnum++) {
556 NihDBusProxy * instance_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
557 upstart->name,
558 instances[jobnum],
559 NULL, NULL);
560
561 nih_local char * instance_name = NULL;
562 if (job_get_name_sync(NULL, instance_proxy, &instance_name) == 0) {
563 gchar * dup = g_strdup(instance_name);
564
565 if (truncate_legacy && g_strcmp0(name, "application-legacy") == 0) {
566 gchar * last_dash = g_strrstr(dup, "-");
567 if (last_dash != NULL) {
568 last_dash[0] = '\0';
569 }
570 }
571
572 g_array_append_val(apps, dup);
573 } else {
574 g_warning("Unable to get name for instance '%s' of job '%s'", instances[jobnum], name);
575 }
576
577 nih_unref(instance_proxy, NULL);
578 }
579}875}
580876
581gchar **877gchar **
582upstart_app_launch_list_running_apps (void)878upstart_app_launch_list_running_apps (void)
583{879{
584 NihDBusProxy * proxy = NULL;880 GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
585881 g_return_val_if_fail(con != NULL, g_new0(gchar *, 1));
586 proxy = nih_proxy_create();
587 if (proxy == NULL) {
588 return g_new0(gchar *, 1);
589 }
590882
591 GArray * apps = g_array_new(TRUE, TRUE, sizeof(gchar *));883 GArray * apps = g_array_new(TRUE, TRUE, sizeof(gchar *));
592884
593 apps_for_job(proxy, "application-legacy", apps, TRUE);885 apps_for_job(con, "application-legacy", apps, TRUE);
594 apps_for_job(proxy, "application-click", apps, FALSE);886 apps_for_job(con, "application-click", apps, FALSE);
595887
596 nih_unref(proxy, NULL);888 g_object_unref(con);
597889
598 return (gchar **)g_array_free(apps, FALSE);890 return (gchar **)g_array_free(apps, FALSE);
599}891}
600892
893typedef struct {
894 GPid pid;
895 const gchar * appid;
896 const gchar * jobname;
897} pid_for_job_t;
898
899static void
900pid_for_job_instance (GDBusConnection * con, GVariant * props_dict, gpointer user_data)
901{
902 GVariant * namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
903 if (namev == NULL) {
904 return;
905 }
906
907 pid_for_job_t * data = (pid_for_job_t *)user_data;
908 gchar * instance_name = g_variant_dup_string(namev, NULL);
909 g_variant_unref(namev);
910
911 if (g_strcmp0(data->jobname, "application-legacy") == 0) {
912 gchar * last_dash = g_strrstr(instance_name, "-");
913 if (last_dash != NULL) {
914 last_dash[0] = '\0';
915 }
916 }
917
918 if (g_strcmp0(instance_name, data->appid) == 0) {
919 GVariant * processv = g_variant_lookup_value(props_dict, "processes", G_VARIANT_TYPE("a(si)"));
920
921 if (processv != NULL) {
922 if (g_variant_n_children(processv) > 0) {
923 GVariant * first_entry = g_variant_get_child_value(processv, 0);
924 GVariant * pidv = g_variant_get_child_value(first_entry, 1);
925
926 data->pid = g_variant_get_int32(pidv);
927
928 g_variant_unref(pidv);
929 g_variant_unref(first_entry);
930 }
931
932 g_variant_unref(processv);
933 }
934 }
935
936 g_free(instance_name);
937}
938
601/* Look for the app for a job */939/* Look for the app for a job */
602static GPid940static GPid
603pid_for_job (NihDBusProxy * upstart, const gchar * job, const gchar * appid)941pid_for_job (GDBusConnection * con, const gchar * jobname, const gchar * appid)
604{942{
605 nih_local char * job_path = NULL;943 pid_for_job_t data = {
606 if (upstart_get_job_by_name_sync(NULL, upstart, job, &job_path) != 0) {944 .jobname = jobname,
607 g_warning("Unable to find job '%s'", job);945 .appid = appid,
608 return 0;946 .pid = 0
609 }947 };
610948
611 NihDBusProxy * job_proxy = nih_dbus_proxy_new(NULL, upstart->connection,949 foreach_job_instance(con, jobname, pid_for_job_instance, &data);
612 upstart->name,950
613 job_path,951 return data.pid;
614 NULL, NULL);
615
616 if (job_proxy == NULL) {
617 g_warning("Unable to build proxy to Job '%s'", job);
618 return 0;
619 }
620
621 nih_local char ** instances;
622 if (job_class_get_all_instances_sync(NULL, job_proxy, &instances) != 0) {
623 g_warning("Unable to get instances for job '%s'", job);
624 nih_unref(job_proxy, NULL);
625 return 0;
626 }
627
628 GPid pid = 0;
629 int jobnum;
630 for (jobnum = 0; instances[jobnum] != NULL && pid == 0; jobnum++) {
631 NihDBusProxy * instance_proxy = nih_dbus_proxy_new(NULL, upstart->connection,
632 upstart->name,
633 instances[jobnum],
634 NULL, NULL);
635
636 nih_local char * instance_name = NULL;
637 if (job_get_name_sync(NULL, instance_proxy, &instance_name) == 0) {
638 if (g_strcmp0(job, "application-legacy") == 0) {
639 gchar * last_dash = g_strrstr(instance_name, "-");
640 if (last_dash != NULL) {
641 last_dash[0] = '\0';
642 }
643 }
644 } else {
645 g_warning("Unable to get name for instance '%s' of job '%s'", instances[jobnum], job);
646 }
647
648 if (g_strcmp0(instance_name, appid) == 0) {
649 nih_local JobProcessesElement ** elements;
650 if (job_get_processes_sync(NULL, instance_proxy, &elements) == 0) {
651 pid = elements[0]->item1;
652 }
653 }
654
655 nih_unref(instance_proxy, NULL);
656 }
657
658 nih_unref(job_proxy, NULL);
659
660 return pid;
661}952}
662953
663GPid954GPid
664upstart_app_launch_get_primary_pid (const gchar * appid)955upstart_app_launch_get_primary_pid (const gchar * appid)
665{956{
666 NihDBusProxy * proxy = NULL;957 g_return_val_if_fail(appid != NULL, 0);
667958
668 proxy = nih_proxy_create();959 GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
669 if (proxy == NULL) {960 g_return_val_if_fail(con != NULL, 0);
670 return 0;
671 }
672961
673 GPid pid = 0;962 GPid pid = 0;
674963
675 if (pid == 0) {964 if (pid == 0) {
676 pid = pid_for_job(proxy, "application-legacy", appid);965 pid = pid_for_job(con, "application-legacy", appid);
677 }966 }
678967
679 if (pid == 0) {968 if (pid == 0) {
680 pid = pid_for_job(proxy, "application-click", appid);969 pid = pid_for_job(con, "application-click", appid);
681 }970 }
682971
683 nih_unref(proxy, NULL);972 g_object_unref(con);
684973
685 return pid;974 return pid;
686}975}
@@ -688,6 +977,8 @@
688gboolean977gboolean
689upstart_app_launch_pid_in_app_id (GPid pid, const gchar * appid)978upstart_app_launch_pid_in_app_id (GPid pid, const gchar * appid)
690{979{
980 g_return_val_if_fail(appid != NULL, FALSE);
981
691 if (pid == 0) {982 if (pid == 0) {
692 return FALSE;983 return FALSE;
693 }984 }
694985
=== modified file 'libupstart-app-launch/upstart-app-launch.h'
--- libupstart-app-launch/upstart-app-launch.h 2014-01-29 02:33:52 +0000
+++ libupstart-app-launch/upstart-app-launch.h 2014-02-11 03:28:22 +0000
@@ -29,35 +29,41 @@
29#endif29#endif
3030
31/**31/**
32 * upstart_app_launch_app_failed_t:32 * UpstartAppLaunchAppFailed:
33 *33 *
34 * Types of failure that we report.34 * Types of failure that we report.
35 */35 */
36enum _upstart_app_launch_app_failed_t {36typedef enum { /*< prefix=UPSTART_APP_LAUNCH_APP_FAILED */
37 UPSTART_APP_LAUNCH_APP_FAILED_CRASH,37 UPSTART_APP_LAUNCH_APP_FAILED_CRASH, /*< nick=crash */
38 UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE,38 UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE, /*< nick=start-failure */
39};39} UpstartAppLaunchAppFailed;
40typedef enum _upstart_app_launch_app_failed_t upstart_app_launch_app_failed_t;40typedef UpstartAppLaunchAppFailed upstart_app_launch_app_failed_t;
4141
42/**42/**
43 * upstart_app_launch_app_observer_t:43 * UpstartAppLaunchAppObserver:
44 *44 *
45 * Function prototype for application observers.45 * Function prototype for application observers.
46 */46 */
47typedef void (*upstart_app_launch_app_observer_t) (const gchar * appid, gpointer user_data);47typedef void (*UpstartAppLaunchAppObserver) (const gchar * appid, gpointer user_data);
48
49/* Backwards compatible. Drop when making API bump. */
50typedef UpstartAppLaunchAppObserver upstart_app_launch_app_observer_t;
4851
49/**52/**
50 * upstart_app_launch_app_failed_observer_t:53 * UpstartAppLaunchAppFailedObserver:
51 *54 *
52 * Function prototype for application failed observers.55 * Function prototype for application failed observers.
53 */56 */
54typedef void (*upstart_app_launch_app_failed_observer_t) (const gchar * appid, upstart_app_launch_app_failed_t failure_type, gpointer user_data);57typedef void (*UpstartAppLaunchAppFailedObserver) (const gchar * appid, UpstartAppLaunchAppFailed failure_type, gpointer user_data);
58
59/* Backwards compatible. Drop when making API bump. */
60typedef UpstartAppLaunchAppFailedObserver upstart_app_launch_app_failed_observer_t;
5561
5662
57/**63/**
58 * upstart_app_launch_start_application:64 * upstart_app_launch_start_application:
59 * @appid: ID of the application to launch65 * @appid: ID of the application to launch
60 * @uris: (allow none): A NULL terminated list of URIs to send to the application66 * @uris: (allow-none) (array zero-terminated=1) (element-type utf8) (transfer none): A NULL terminated list of URIs to send to the application
61 *67 *
62 * Asks upstart to launch an application.68 * Asks upstart to launch an application.
63 *69 *
@@ -81,8 +87,8 @@
8187
82/**88/**
83 * upstart_app_launch_observer_add_app_starting:89 * upstart_app_launch_observer_add_app_starting:
84 * @observer: Callback when an application is about to start90 * @observer: (scope notified): Callback when an application is about to start
85 * @user_data: (allow none): Data to pass to the observer91 * @user_data: (closure) (allow-none): Data to pass to the observer
86 *92 *
87 * Sets up a callback to get called each time an application93 * Sets up a callback to get called each time an application
88 * is about to start. The application will not start until the94 * is about to start. The application will not start until the
@@ -90,50 +96,50 @@
90 *96 *
91 * Return value: Whether adding the observer was successful.97 * Return value: Whether adding the observer was successful.
92 */98 */
93gboolean upstart_app_launch_observer_add_app_starting (upstart_app_launch_app_observer_t observer,99gboolean upstart_app_launch_observer_add_app_starting (UpstartAppLaunchAppObserver observer,
94 gpointer user_data);100 gpointer user_data);
95/**101/**
96 * upstart_app_launch_observer_add_app_started:102 * upstart_app_launch_observer_add_app_started:
97 * @observer: Callback when an application started103 * @observer: (scope notified): Callback when an application started
98 * @user_data: (allow none): Data to pass to the observer104 * @user_data: (closure) (allow-none): Data to pass to the observer
99 *105 *
100 * Sets up a callback to get called each time an application106 * Sets up a callback to get called each time an application
101 * has been started.107 * has been started.
102 *108 *
103 * Return value: Whether adding the observer was successful.109 * Return value: Whether adding the observer was successful.
104 */110 */
105gboolean upstart_app_launch_observer_add_app_started (upstart_app_launch_app_observer_t observer,111gboolean upstart_app_launch_observer_add_app_started (UpstartAppLaunchAppObserver observer,
106 gpointer user_data);112 gpointer user_data);
107/**113/**
108 * upstart_app_launch_observer_add_app_stop:114 * upstart_app_launch_observer_add_app_stop:
109 * @observer: Callback when an application stops115 * @observer: (scope notified): Callback when an application stops
110 * @user_data: (allow none): Data to pass to the observer116 * @user_data: (closure) (allow-none): Data to pass to the observer
111 *117 *
112 * Sets up a callback to get called each time an application118 * Sets up a callback to get called each time an application
113 * stops.119 * stops.
114 *120 *
115 * Return value: Whether adding the observer was successful.121 * Return value: Whether adding the observer was successful.
116 */122 */
117gboolean upstart_app_launch_observer_add_app_stop (upstart_app_launch_app_observer_t observer,123gboolean upstart_app_launch_observer_add_app_stop (UpstartAppLaunchAppObserver observer,
118 gpointer user_data);124 gpointer user_data);
119125
120/**126/**
121 * upstart_app_launch_observer_add_app_focus:127 * upstart_app_launch_observer_add_app_focus:
122 * @observer: Callback when an application is started for the second time128 * @observer: (scope notified): Callback when an application is started for the second time
123 * @user_data: (allow none): Data to pass to the observer129 * @user_data: (closure) (allow-none): Data to pass to the observer
124 *130 *
125 * Sets up a callback to get called each time an app gets called131 * Sets up a callback to get called each time an app gets called
126 * that is already running, so we request it to be focused again.132 * that is already running, so we request it to be focused again.
127 *133 *
128 * Return value: Whether adding the observer was successful.134 * Return value: Whether adding the observer was successful.
129 */135 */
130gboolean upstart_app_launch_observer_add_app_focus (upstart_app_launch_app_observer_t observer,136gboolean upstart_app_launch_observer_add_app_focus (UpstartAppLaunchAppObserver observer,
131 gpointer user_data);137 gpointer user_data);
132138
133/**139/**
134 * upstart_app_launch_observer_add_app_resume:140 * upstart_app_launch_observer_add_app_resume:
135 * @observer: Callback when an application is started and possibly asleep141 * @observer: (scope notified): Callback when an application is started and possibly asleep
136 * @user_data: (allow none): Data to pass to the observer142 * @user_data: (closure) (allow-none): Data to pass to the observer
137 *143 *
138 * Sets up a callback to get called each time an app gets called144 * Sets up a callback to get called each time an app gets called
139 * that is already running, so we request it to be given CPU time.145 * that is already running, so we request it to be given CPU time.
@@ -141,96 +147,96 @@
141 *147 *
142 * Return value: Whether adding the observer was successful.148 * Return value: Whether adding the observer was successful.
143 */149 */
144gboolean upstart_app_launch_observer_add_app_resume (upstart_app_launch_app_observer_t observer,150gboolean upstart_app_launch_observer_add_app_resume (UpstartAppLaunchAppObserver observer,
145 gpointer user_data);151 gpointer user_data);
146152
147/**153/**
148 * upstart_app_launch_observer_add_app_failed:154 * upstart_app_launch_observer_add_app_failed:
149 * @observer: Callback when an application fails155 * @observer: (scope notified): Callback when an application fails
150 * @user_data: (allow none): Data to pass to the observer156 * @user_data: (allow-none) (closure): Data to pass to the observer
151 *157 *
152 * Sets up a callback to get called each time an application158 * Sets up a callback to get called each time an application
153 * stops via failure.159 * stops via failure.
154 *160 *
155 * Return value: Whether adding the observer was successful.161 * Return value: Whether adding the observer was successful.
156 */162 */
157gboolean upstart_app_launch_observer_add_app_failed (upstart_app_launch_app_failed_observer_t observer,163gboolean upstart_app_launch_observer_add_app_failed (UpstartAppLaunchAppFailedObserver observer,
158 gpointer user_data);164 gpointer user_data);
159165
160/**166/**
161 * upstart_app_launch_observer_delete_app_starting:167 * upstart_app_launch_observer_delete_app_starting:
162 * @observer: Callback to remove168 * @observer: (scope notified): Callback to remove
163 * @user_data: (allow none): Data that was passed to the observer169 * @user_data: (closure) (allow-none): Data that was passed to the observer
164 *170 *
165 * Removes a previously registered callback to ensure it no longer171 * Removes a previously registered callback to ensure it no longer
166 * gets signaled.172 * gets signaled.
167 *173 *
168 * Return value: Whether deleting the observer was successful.174 * Return value: Whether deleting the observer was successful.
169 */175 */
170gboolean upstart_app_launch_observer_delete_app_starting (upstart_app_launch_app_observer_t observer,176gboolean upstart_app_launch_observer_delete_app_starting (UpstartAppLaunchAppObserver observer,
171 gpointer user_data);177 gpointer user_data);
172/**178/**
173 * upstart_app_launch_observer_delete_app_started:179 * upstart_app_launch_observer_delete_app_started:
174 * @observer: Callback to remove180 * @observer: (scope notified): Callback to remove
175 * @user_data: (allow none): Data that was passed to the observer181 * @user_data: (closure) (allow-none): Data that was passed to the observer
176 *182 *
177 * Removes a previously registered callback to ensure it no longer183 * Removes a previously registered callback to ensure it no longer
178 * gets signaled.184 * gets signaled.
179 *185 *
180 * Return value: Whether deleting the observer was successful.186 * Return value: Whether deleting the observer was successful.
181 */187 */
182gboolean upstart_app_launch_observer_delete_app_started (upstart_app_launch_app_observer_t observer,188gboolean upstart_app_launch_observer_delete_app_started (UpstartAppLaunchAppObserver observer,
183 gpointer user_data);189 gpointer user_data);
184/**190/**
185 * upstart_app_launch_observer_delete_app_stop:191 * upstart_app_launch_observer_delete_app_stop:
186 * @observer: Callback to remove192 * @observer: (scope notified): Callback to remove
187 * @user_data: (allow none): Data that was passed to the observer193 * @user_data: (closure) (allow-none): Data that was passed to the observer
188 *194 *
189 * Removes a previously registered callback to ensure it no longer195 * Removes a previously registered callback to ensure it no longer
190 * gets signaled.196 * gets signaled.
191 *197 *
192 * Return value: Whether deleting the observer was successful.198 * Return value: Whether deleting the observer was successful.
193 */199 */
194gboolean upstart_app_launch_observer_delete_app_stop (upstart_app_launch_app_observer_t observer,200gboolean upstart_app_launch_observer_delete_app_stop (UpstartAppLaunchAppObserver observer,
195 gpointer user_data);201 gpointer user_data);
196202
197/**203/**
198 * upstart_app_launch_observer_delete_app_focus:204 * upstart_app_launch_observer_delete_app_focus:
199 * @observer: Callback to remove205 * @observer: (scope notified): Callback to remove
200 * @user_data: (allow none): Data that was passed to the observer206 * @user_data: (closure) (allow-none): Data that was passed to the observer
201 *207 *
202 * Removes a previously registered callback to ensure it no longer208 * Removes a previously registered callback to ensure it no longer
203 * gets signaled.209 * gets signaled.
204 *210 *
205 * Return value: Whether deleting the observer was successful.211 * Return value: Whether deleting the observer was successful.
206 */212 */
207gboolean upstart_app_launch_observer_delete_app_focus (upstart_app_launch_app_observer_t observer,213gboolean upstart_app_launch_observer_delete_app_focus (UpstartAppLaunchAppObserver observer,
208 gpointer user_data);214 gpointer user_data);
209215
210/**216/**
211 * upstart_app_launch_observer_delete_app_resume:217 * upstart_app_launch_observer_delete_app_resume:
212 * @observer: Callback to remove218 * @observer: (scope notified): Callback to remove
213 * @user_data: (allow none): Data that was passed to the observer219 * @user_data: (closure) (allow-none): Data that was passed to the observer
214 *220 *
215 * Removes a previously registered callback to ensure it no longer221 * Removes a previously registered callback to ensure it no longer
216 * gets signaled.222 * gets signaled.
217 *223 *
218 * Return value: Whether deleting the observer was successful.224 * Return value: Whether deleting the observer was successful.
219 */225 */
220gboolean upstart_app_launch_observer_delete_app_resume (upstart_app_launch_app_observer_t observer,226gboolean upstart_app_launch_observer_delete_app_resume (UpstartAppLaunchAppObserver observer,
221 gpointer user_data);227 gpointer user_data);
222228
223/**229/**
224 * upstart_app_launch_observer_delete_app_failed:230 * upstart_app_launch_observer_delete_app_failed:
225 * @observer: Callback to remove231 * @observer: (scope notified): Callback to remove
226 * @user_data: (allow none): Data to pass to the observer232 * @user_data: (closure) (allow-none): Data to pass to the observer
227 *233 *
228 * Removes a previously registered callback to ensure it no longer234 * Removes a previously registered callback to ensure it no longer
229 * gets signaled.235 * gets signaled.
230 *236 *
231 * Return value: Whether deleting the observer was successful.237 * Return value: Whether deleting the observer was successful.
232 */238 */
233gboolean upstart_app_launch_observer_delete_app_failed (upstart_app_launch_app_failed_observer_t observer,239gboolean upstart_app_launch_observer_delete_app_failed (UpstartAppLaunchAppFailedObserver observer,
234 gpointer user_data);240 gpointer user_data);
235/**241/**
236 * upstart_app_launch_list_running_apps:242 * upstart_app_launch_list_running_apps:
237243
=== removed file 'second-exec-trace.tp'
--- second-exec-trace.tp 2013-12-04 17:32:23 +0000
+++ second-exec-trace.tp 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
1
2TRACEPOINT_EVENT(upstart_app_launch, second_exec_start, TP_ARGS(0), TP_FIELDS())
3TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_resume, TP_ARGS(0), TP_FIELDS())
4TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_complete, TP_ARGS(0), TP_FIELDS())
5TRACEPOINT_EVENT(upstart_app_launch, second_exec_resume_timeout, TP_ARGS(0), TP_FIELDS())
6TRACEPOINT_EVENT(upstart_app_launch, second_exec_emit_focus, TP_ARGS(0), TP_FIELDS())
7TRACEPOINT_EVENT(upstart_app_launch, second_exec_finish, TP_ARGS(0), TP_FIELDS())
8TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_dbus_names, TP_ARGS(0), TP_FIELDS())
9TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_primary_pid, TP_ARGS(0), TP_FIELDS())
10TRACEPOINT_EVENT(upstart_app_launch, second_exec_request_pid, TP_ARGS(0), TP_FIELDS())
11TRACEPOINT_EVENT(upstart_app_launch, second_exec_got_pid, TP_ARGS(0), TP_FIELDS())
12TRACEPOINT_EVENT(upstart_app_launch, second_exec_contact_app, TP_ARGS(0), TP_FIELDS())
13TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_contacted, TP_ARGS(0), TP_FIELDS())
14TRACEPOINT_EVENT(upstart_app_launch, second_exec_app_error, TP_ARGS(0), TP_FIELDS())
15TRACEPOINT_EVENT(upstart_app_launch, second_exec_connection_complete, TP_ARGS(0), TP_FIELDS())
16
170
=== removed file 'second-exec.c'
--- second-exec.c 2013-12-05 17:08:13 +0000
+++ second-exec.c 1970-01-01 00:00:00 +0000
@@ -1,40 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#include "second-exec-core.h"
21
22int
23main (int argc, char * argv[])
24{
25 if (argc != 1) {
26 g_error("Should be called as: %s", argv[0]);
27 return 1;
28 }
29
30 const gchar * appid = g_getenv("APP_ID");
31 const gchar * appuris = g_getenv("APP_URIS");
32
33 g_setenv("LTTNG_UST_REGISTER_TIMEOUT", "0", FALSE); /* Set to zero if not set */
34
35 if (second_exec(appid, appuris)) {
36 return 0;
37 } else {
38 return 1;
39 }
40}
410
=== modified file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 2014-01-13 15:16:24 +0000
+++ tests/CMakeLists.txt 2014-02-11 03:28:22 +0000
@@ -25,16 +25,6 @@
2525
26add_test (helper-handshake-test helper-handshake-test)26add_test (helper-handshake-test helper-handshake-test)
2727
28# Second Exec Test
29
30include_directories("${CMAKE_SOURCE_DIR}/libupstart-app-launch")
31
32add_executable (second-exec-test
33 second-exec-test.cc
34 upstart-app-launch-mock.c)
35target_link_libraries (second-exec-test helpers gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} upstart-launcher second-exec-core)
36add_test (second-exec-test second-exec-test)
37
38# libUAL Test28# libUAL Test
3929
40include_directories("${CMAKE_SOURCE_DIR}/libupstart-app-launch")30include_directories("${CMAKE_SOURCE_DIR}/libupstart-app-launch")
@@ -43,14 +33,16 @@
43 libual-test.cc)33 libual-test.cc)
44target_link_libraries (libual-test helpers gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} upstart-launcher)34target_link_libraries (libual-test helpers gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} upstart-launcher)
4535
46# NOTE: Tests are broken into individual runs to avoid problems with libdbus36add_test (NAME libual-test COMMAND libual-test)
47add_test (NAME libual-test-start COMMAND libual-test --gtest_filter=*StartApplication)37
48add_test (NAME libual-test-stop COMMAND libual-test --gtest_filter=*StopApplication)38# Failure Test
49add_test (NAME libual-test-pid COMMAND libual-test --gtest_filter=*ApplicationPid)39
50add_test (NAME libual-test-app-id COMMAND libual-test --gtest_filter=*ApplicationId)40add_definitions ( -DAPP_FAILED_TOOL="${CMAKE_BINARY_DIR}/application-failed" )
51add_test (NAME libual-test-list COMMAND libual-test --gtest_filter=*ApplicationList)41
52add_test (NAME libual-test-observer COMMAND libual-test --gtest_filter=*StartStopObserver)42add_executable (failure-test
53add_test (NAME libual-test-starting COMMAND libual-test --gtest_filter=*StartingResponses)43 failure-test.cc)
44target_link_libraries (failure-test gtest ${GTEST_LIBS} upstart-launcher)
45add_test (failure-test failure-test)
5446
55# ZG Test47# ZG Test
5648
5749
=== added file 'tests/applications/multiple.desktop'
--- tests/applications/multiple.desktop 1970-01-01 00:00:00 +0000
+++ tests/applications/multiple.desktop 2014-02-11 03:28:22 +0000
@@ -0,0 +1,8 @@
1[Desktop Entry]
2Name=Multiple
3Type=Application
4Exec=multiple
5NoDisplay=false
6Hidden=false
7Terminal=false
8X-Ubuntu-Single-Instance=false
09
=== added file 'tests/applications/single.desktop'
--- tests/applications/single.desktop 1970-01-01 00:00:00 +0000
+++ tests/applications/single.desktop 2014-02-11 03:28:22 +0000
@@ -0,0 +1,8 @@
1[Desktop Entry]
2Name=Single
3Type=Application
4Exec=single
5NoDisplay=false
6Hidden=false
7Terminal=false
8X-Ubuntu-Single-Instance=true
09
=== added file 'tests/failure-test.cc'
--- tests/failure-test.cc 1970-01-01 00:00:00 +0000
+++ tests/failure-test.cc 2014-02-11 03:28:22 +0000
@@ -0,0 +1,151 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#include <gtest/gtest.h>
21#include <glib/gstdio.h>
22#include <gio/gio.h>
23#include <upstart-app-launch.h>
24
25class FailureTest : public ::testing::Test
26{
27 private:
28 GTestDBus * testbus = NULL;
29
30 protected:
31 virtual void SetUp() {
32 testbus = g_test_dbus_new(G_TEST_DBUS_NONE);
33 g_test_dbus_up(testbus);
34 }
35
36 virtual void TearDown() {
37 g_test_dbus_down(testbus);
38 g_clear_object(&testbus);
39 return;
40 }
41
42 static gboolean pause_helper (gpointer pmainloop) {
43 g_main_loop_quit(static_cast<GMainLoop *>(pmainloop));
44 return G_SOURCE_REMOVE;
45 }
46
47 void pause (guint time) {
48 if (time > 0) {
49 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
50 g_timeout_add(time, pause_helper, mainloop);
51
52 g_main_loop_run(mainloop);
53
54 g_main_loop_unref(mainloop);
55 }
56
57 while (g_main_pending()) {
58 g_main_iteration(TRUE);
59 }
60 }
61};
62
63static void
64failed_observer (const gchar * appid, upstart_app_launch_app_failed_t reason, gpointer user_data)
65{
66 if (reason == UPSTART_APP_LAUNCH_APP_FAILED_CRASH) {
67 std::string * last = static_cast<std::string *>(user_data);
68 *last = appid;
69 }
70 return;
71}
72
73TEST_F(FailureTest, CrashTest)
74{
75 g_setenv("EXIT_STATUS", "-100", TRUE);
76 g_setenv("JOB", "application-click", TRUE);
77 g_setenv("INSTANCE", "foo", TRUE);
78
79 std::string last_observer;
80 ASSERT_TRUE(upstart_app_launch_observer_add_app_failed(failed_observer, &last_observer));
81
82 /* Status based */
83 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
84 pause(100);
85
86 EXPECT_EQ("foo", last_observer);
87
88 last_observer.clear();
89 g_unsetenv("EXIT_STATUS");
90 g_setenv("EXIT_SIGNAL", "KILL", TRUE);
91
92 /* Signal based */
93 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
94 pause(100);
95
96 EXPECT_EQ("foo", last_observer);
97
98 ASSERT_TRUE(upstart_app_launch_observer_delete_app_failed(failed_observer, &last_observer));
99
100 return;
101}
102
103TEST_F(FailureTest, LegacyTest)
104{
105 g_setenv("EXIT_STATUS", "-100", TRUE);
106 g_setenv("JOB", "application-legacy", TRUE);
107 g_setenv("INSTANCE", "foo-1234", TRUE);
108
109 std::string last_observer;
110 ASSERT_TRUE(upstart_app_launch_observer_add_app_failed(failed_observer, &last_observer));
111
112 /* Status based */
113 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
114 pause(100);
115
116 EXPECT_EQ("foo", last_observer);
117
118 ASSERT_TRUE(upstart_app_launch_observer_delete_app_failed(failed_observer, &last_observer));
119
120 return;
121}
122
123static void
124failed_start_observer (const gchar * appid, upstart_app_launch_app_failed_t reason, gpointer user_data)
125{
126 if (reason == UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE) {
127 std::string * last = static_cast<std::string *>(user_data);
128 *last = appid;
129 }
130 return;
131}
132
133TEST_F(FailureTest, StartTest)
134{
135 g_setenv("JOB", "application-click", TRUE);
136 g_setenv("INSTANCE", "foo", TRUE);
137 g_unsetenv("EXIT_STATUS");
138 g_unsetenv("EXIT_SIGNAL");
139
140 std::string last_observer;
141 ASSERT_TRUE(upstart_app_launch_observer_add_app_failed(failed_start_observer, &last_observer));
142
143 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
144 pause(100);
145
146 EXPECT_EQ("foo", last_observer);
147
148 ASSERT_TRUE(upstart_app_launch_observer_delete_app_failed(failed_start_observer, &last_observer));
149
150 return;
151}
0152
=== modified file 'tests/libual-test.cc'
--- tests/libual-test.cc 2014-01-29 02:24:06 +0000
+++ tests/libual-test.cc 2014-02-11 03:28:22 +0000
@@ -31,6 +31,26 @@
31 DbusTestService * service = NULL;31 DbusTestService * service = NULL;
32 DbusTestDbusMock * mock = NULL;32 DbusTestDbusMock * mock = NULL;
33 GDBusConnection * bus = NULL;33 GDBusConnection * bus = NULL;
34 std::string last_focus_appid;
35 std::string last_resume_appid;
36 guint resume_timeout = 0;
37
38 private:
39 static void focus_cb (const gchar * appid, gpointer user_data) {
40 g_debug("Focus Callback: %s", appid);
41 LibUAL * _this = static_cast<LibUAL *>(user_data);
42 _this->last_focus_appid = appid;
43 }
44
45 static void resume_cb (const gchar * appid, gpointer user_data) {
46 g_debug("Resume Callback: %s", appid);
47 LibUAL * _this = static_cast<LibUAL *>(user_data);
48 _this->last_resume_appid = appid;
49
50 if (_this->resume_timeout > 0) {
51 _this->pause(_this->resume_timeout);
52 }
53 }
3454
35 protected:55 protected:
36 /* Useful debugging stuff, but not on by default. You really want to56 /* Useful debugging stuff, but not on by default. You really want to
@@ -48,6 +68,12 @@
48 }68 }
4969
50 virtual void SetUp() {70 virtual void SetUp() {
71 gchar * linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL);
72 g_setenv("UPSTART_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE);
73 g_free(linkfarmpath);
74
75 g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
76
51 service = dbus_test_service_new(NULL);77 service = dbus_test_service_new(NULL);
52 g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);78 g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
53 const gchar * oldpath = g_getenv("PATH");79 const gchar * oldpath = g_getenv("PATH");
@@ -81,6 +107,14 @@
81 DbusTestDbusMockObject * jobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);107 DbusTestDbusMockObject * jobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
82108
83 dbus_test_dbus_mock_object_add_method(mock, jobobj,109 dbus_test_dbus_mock_object_add_method(mock, jobobj,
110 "Start",
111 G_VARIANT_TYPE("(asb)"),
112 NULL,
113 "if args[0][0] == 'APP_ID=foo':"
114 " raise dbus.exceptions.DBusException('Foo running', name='com.ubuntu.Upstart0_6.Error.AlreadyStarted')",
115 NULL);
116
117 dbus_test_dbus_mock_object_add_method(mock, jobobj,
84 "Stop",118 "Stop",
85 G_VARIANT_TYPE("(asb)"),119 G_VARIANT_TYPE("(asb)"),
86 NULL,120 NULL,
@@ -100,15 +134,24 @@
100 G_VARIANT_TYPE_STRING,134 G_VARIANT_TYPE_STRING,
101 g_variant_new_string("foo"),135 g_variant_new_string("foo"),
102 NULL);136 NULL);
137 gchar * process_var = g_strdup_printf("[('main', %d)]", getpid());
103 dbus_test_dbus_mock_object_add_property(mock, instobj,138 dbus_test_dbus_mock_object_add_property(mock, instobj,
104 "processes",139 "processes",
105 G_VARIANT_TYPE("a(si)"),140 G_VARIANT_TYPE("a(si)"),
106 g_variant_new_parsed("[('main', 1234)]"),141 g_variant_new_parsed(process_var),
107 NULL);142 NULL);
143 g_free(process_var);
108144
109 DbusTestDbusMockObject * ljobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);145 DbusTestDbusMockObject * ljobobj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
110146
111 dbus_test_dbus_mock_object_add_method(mock, ljobobj,147 dbus_test_dbus_mock_object_add_method(mock, ljobobj,
148 "Start",
149 G_VARIANT_TYPE("(asb)"),
150 NULL,
151 "",
152 NULL);
153
154 dbus_test_dbus_mock_object_add_method(mock, ljobobj,
112 "Stop",155 "Stop",
113 G_VARIANT_TYPE("(asb)"),156 G_VARIANT_TYPE("(asb)"),
114 NULL,157 NULL,
@@ -140,9 +183,15 @@
140 bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);183 bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
141 g_dbus_connection_set_exit_on_close(bus, FALSE);184 g_dbus_connection_set_exit_on_close(bus, FALSE);
142 g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);185 g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);
186
187 ASSERT_TRUE(upstart_app_launch_observer_add_app_focus(focus_cb, this));
188 ASSERT_TRUE(upstart_app_launch_observer_add_app_resume(resume_cb, this));
143 }189 }
144190
145 virtual void TearDown() {191 virtual void TearDown() {
192 upstart_app_launch_observer_delete_app_focus(focus_cb, this);
193 upstart_app_launch_observer_delete_app_resume(resume_cb, this);
194
146 g_clear_object(&mock);195 g_clear_object(&mock);
147 g_clear_object(&service);196 g_clear_object(&service);
148197
@@ -150,12 +199,10 @@
150199
151 unsigned int cleartry = 0;200 unsigned int cleartry = 0;
152 while (bus != NULL && cleartry < 100) {201 while (bus != NULL && cleartry < 100) {
153 g_usleep(100000);202 pause(100);
154 while (g_main_pending()) {
155 g_main_iteration(TRUE);
156 }
157 cleartry++;203 cleartry++;
158 }204 }
205 ASSERT_EQ(bus, nullptr);
159 }206 }
160207
161 bool check_env (GVariant * env_array, const gchar * var, const gchar * value) {208 bool check_env (GVariant * env_array, const gchar * var, const gchar * value) {
@@ -189,18 +236,17 @@
189 }236 }
190237
191 static gboolean pause_helper (gpointer pmainloop) {238 static gboolean pause_helper (gpointer pmainloop) {
192 g_main_loop_quit((GMainLoop *)pmainloop);239 g_main_loop_quit(static_cast<GMainLoop *>(pmainloop));
193 return G_SOURCE_REMOVE;240 return G_SOURCE_REMOVE;
194 }241 }
195242
196 void pause (guint time) {243 void pause (guint time) {
197 if (time > 0) {244 if (time > 0) {
198 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);245 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
199 guint timer = g_timeout_add(time, pause_helper, mainloop);246 g_timeout_add(time, pause_helper, mainloop);
200247
201 g_main_loop_run(mainloop);248 g_main_loop_run(mainloop);
202249
203 g_source_remove(timer);
204 g_main_loop_unref(mainloop);250 g_main_loop_unref(mainloop);
205 }251 }
206252
@@ -212,35 +258,31 @@
212258
213TEST_F(LibUAL, StartApplication)259TEST_F(LibUAL, StartApplication)
214{260{
215 DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);261 DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_click", "com.ubuntu.Upstart0_6.Job", NULL);
216262
217 /* Basic make sure we can send the event */263 /* Basic make sure we can send the event */
218 ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));264 ASSERT_TRUE(upstart_app_launch_start_application("foolike", NULL));
219 ASSERT_EQ(dbus_test_dbus_mock_object_check_method_call(mock, obj, "EmitEvent", NULL, NULL), 1);265 EXPECT_EQ(1, dbus_test_dbus_mock_object_check_method_call(mock, obj, "Start", NULL, NULL));
220266
221 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));267 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
222268
223 /* Now look at the details of the call */269 /* Now look at the details of the call */
224 ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));270 ASSERT_TRUE(upstart_app_launch_start_application("foolike", NULL));
225271
226 guint len = 0;272 guint len = 0;
227 const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "EmitEvent", &len, NULL);273 const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
228 ASSERT_NE(calls, nullptr);274 EXPECT_NE(nullptr, calls);
229 ASSERT_EQ(len, 1);275 EXPECT_EQ(1, len);
230276
231 ASSERT_STREQ(calls->name, "EmitEvent");277 EXPECT_STREQ("Start", calls->name);
232 ASSERT_EQ(g_variant_n_children(calls->params), 3);278 EXPECT_EQ(2, g_variant_n_children(calls->params));
233279
234 GVariant * name = g_variant_get_child_value(calls->params, 0);280 GVariant * block = g_variant_get_child_value(calls->params, 1);
235 ASSERT_STREQ(g_variant_get_string(name, NULL), "application-start");281 EXPECT_TRUE(g_variant_get_boolean(block));
236 g_variant_unref(name);
237
238 GVariant * block = g_variant_get_child_value(calls->params, 2);
239 ASSERT_FALSE(g_variant_get_boolean(block));
240 g_variant_unref(block);282 g_variant_unref(block);
241283
242 GVariant * env = g_variant_get_child_value(calls->params, 1);284 GVariant * env = g_variant_get_child_value(calls->params, 0);
243 ASSERT_TRUE(check_env(env, "APP_ID", "foo"));285 EXPECT_TRUE(check_env(env, "APP_ID", "foolike"));
244 g_variant_unref(env);286 g_variant_unref(env);
245287
246 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));288 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
@@ -252,16 +294,16 @@
252 "file:///home/phablet/test.txt",294 "file:///home/phablet/test.txt",
253 NULL295 NULL
254 };296 };
255 ASSERT_TRUE(upstart_app_launch_start_application("foo", urls));297 ASSERT_TRUE(upstart_app_launch_start_application("foolike", urls));
256298
257 len = 0;299 len = 0;
258 calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "EmitEvent", &len, NULL);300 calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
259 ASSERT_NE(calls, nullptr);301 EXPECT_NE(nullptr, calls);
260 ASSERT_EQ(len, 1);302 EXPECT_EQ(1, len);
261303
262 env = g_variant_get_child_value(calls->params, 1);304 env = g_variant_get_child_value(calls->params, 0);
263 ASSERT_TRUE(check_env(env, "APP_ID", "foo"));305 EXPECT_TRUE(check_env(env, "APP_ID", "foolike"));
264 ASSERT_TRUE(check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));306 EXPECT_TRUE(check_env(env, "APP_URIS", "'http://ubuntu.com/' 'https://ubuntu.com/' 'file:///home/phablet/test.txt'"));
265 g_variant_unref(env);307 g_variant_unref(env);
266308
267 return;309 return;
@@ -279,10 +321,10 @@
279321
280TEST_F(LibUAL, ApplicationPid)322TEST_F(LibUAL, ApplicationPid)
281{323{
282 ASSERT_EQ(upstart_app_launch_get_primary_pid("foo"), 1234);324 EXPECT_EQ(upstart_app_launch_get_primary_pid("foo"), getpid());
283 ASSERT_EQ(upstart_app_launch_get_primary_pid("bar"), 5678);325 EXPECT_EQ(upstart_app_launch_get_primary_pid("bar"), 5678);
284 ASSERT_TRUE(upstart_app_launch_pid_in_app_id(1234, "foo"));326 EXPECT_TRUE(upstart_app_launch_pid_in_app_id(getpid(), "foo"));
285 ASSERT_FALSE(upstart_app_launch_pid_in_app_id(5678, "foo"));327 EXPECT_FALSE(upstart_app_launch_pid_in_app_id(5678, "foo"));
286}328}
287329
288TEST_F(LibUAL, ApplicationId)330TEST_F(LibUAL, ApplicationId)
@@ -363,7 +405,6 @@
363405
364 ASSERT_TRUE(upstart_app_launch_observer_add_app_started(observer_cb, &start_data));406 ASSERT_TRUE(upstart_app_launch_observer_add_app_started(observer_cb, &start_data));
365 ASSERT_TRUE(upstart_app_launch_observer_add_app_stop(observer_cb, &stop_data));407 ASSERT_TRUE(upstart_app_launch_observer_add_app_stop(observer_cb, &stop_data));
366 ASSERT_FALSE(upstart_app_launch_observer_add_app_failed(NULL, NULL)); /* Not yet implemented */
367408
368 DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);409 DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
369410
@@ -473,7 +514,6 @@
473 /* Remove */514 /* Remove */
474 ASSERT_TRUE(upstart_app_launch_observer_delete_app_started(observer_cb, &start_data));515 ASSERT_TRUE(upstart_app_launch_observer_delete_app_started(observer_cb, &start_data));
475 ASSERT_TRUE(upstart_app_launch_observer_delete_app_stop(observer_cb, &stop_data));516 ASSERT_TRUE(upstart_app_launch_observer_delete_app_stop(observer_cb, &stop_data));
476 ASSERT_FALSE(upstart_app_launch_observer_delete_app_failed(NULL, NULL)); /* Not yet implemented */
477}517}
478518
479static GDBusMessage *519static GDBusMessage *
@@ -527,3 +567,241 @@
527 g_dbus_connection_remove_filter(session, filter);567 g_dbus_connection_remove_filter(session, filter);
528 g_object_unref(session);568 g_object_unref(session);
529}569}
570
571TEST_F(LibUAL, AppIdTest)
572{
573 ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
574 pause(50); /* Ensure all the events come through */
575 EXPECT_EQ("foo", this->last_focus_appid);
576 EXPECT_EQ("foo", this->last_resume_appid);
577}
578
579GDBusMessage *
580filter_func_good (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
581{
582 if (!incomming) {
583 return message;
584 }
585
586 if (g_strcmp0(g_dbus_message_get_path(message), (gchar *)user_data) == 0) {
587 GDBusMessage * reply = g_dbus_message_new_method_reply(message);
588 g_dbus_connection_send_message(conn, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
589 g_object_unref(message);
590 return NULL;
591 }
592
593 return message;
594}
595
596TEST_F(LibUAL, UrlSendTest)
597{
598 GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
599 guint filter = g_dbus_connection_add_filter(session,
600 filter_func_good,
601 (gpointer)"/foo",
602 NULL);
603
604 const gchar * uris[] = {
605 "http://www.test.com",
606 NULL
607 };
608 ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
609 pause(100); /* Ensure all the events come through */
610
611 EXPECT_EQ("foo", this->last_focus_appid);
612 EXPECT_EQ("foo", this->last_resume_appid);
613
614 g_dbus_connection_remove_filter(session, filter);
615 g_object_unref(session);
616}
617
618TEST_F(LibUAL, UrlSendNoObjectTest)
619{
620 const gchar * uris[] = {
621 "http://www.test.com",
622 NULL
623 };
624
625 ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
626 pause(100); /* Ensure all the events come through */
627
628 EXPECT_EQ("foo", this->last_focus_appid);
629 EXPECT_EQ("foo", this->last_resume_appid);
630}
631
632TEST_F(LibUAL, UnityTimeoutTest)
633{
634 this->resume_timeout = 100;
635
636 ASSERT_TRUE(upstart_app_launch_start_application("foo", NULL));
637 pause(1000); /* Ensure all the events come through */
638 EXPECT_EQ("foo", this->last_focus_appid);
639 EXPECT_EQ("foo", this->last_resume_appid);
640}
641
642TEST_F(LibUAL, UnityTimeoutUriTest)
643{
644 this->resume_timeout = 200;
645
646 const gchar * uris[] = {
647 "http://www.test.com",
648 NULL
649 };
650
651 ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
652 pause(1000); /* Ensure all the events come through */
653 EXPECT_EQ("foo", this->last_focus_appid);
654 EXPECT_EQ("foo", this->last_resume_appid);
655}
656
657GDBusMessage *
658filter_respawn (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
659{
660 if (g_strcmp0(g_dbus_message_get_member(message), "UnityResumeResponse") == 0) {
661 g_object_unref(message);
662 return NULL;
663 }
664
665 return message;
666}
667
668TEST_F(LibUAL, UnityLostTest)
669{
670 GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
671 guint filter = g_dbus_connection_add_filter(session,
672 filter_respawn,
673 NULL,
674 NULL);
675
676 guint start = g_get_monotonic_time();
677
678 const gchar * uris[] = {
679 "http://www.test.com",
680 NULL
681 };
682
683 ASSERT_TRUE(upstart_app_launch_start_application("foo", uris));
684
685 guint end = g_get_monotonic_time();
686
687 EXPECT_LT(end - start, 600 * 1000);
688
689 pause(1000); /* Ensure all the events come through */
690
691 EXPECT_EQ("foo", this->last_focus_appid);
692 EXPECT_EQ("foo", this->last_resume_appid);
693
694 g_dbus_connection_remove_filter(session, filter);
695 g_object_unref(session);
696}
697
698
699TEST_F(LibUAL, LegacySingleInstance)
700{
701 DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/com/test/application_legacy", "com.ubuntu.Upstart0_6.Job", NULL);
702
703 /* Check for a single-instance app */
704 ASSERT_TRUE(upstart_app_launch_start_application("single", NULL));
705
706 guint len = 0;
707 const DbusTestDbusMockCall * calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
708 EXPECT_NE(nullptr, calls);
709 EXPECT_EQ(1, len);
710
711 EXPECT_STREQ("Start", calls->name);
712 EXPECT_EQ(2, g_variant_n_children(calls->params));
713
714 GVariant * block = g_variant_get_child_value(calls->params, 1);
715 EXPECT_TRUE(g_variant_get_boolean(block));
716 g_variant_unref(block);
717
718 GVariant * env = g_variant_get_child_value(calls->params, 0);
719 EXPECT_TRUE(check_env(env, "APP_ID", "single"));
720 EXPECT_TRUE(check_env(env, "INSTANCE_ID", ""));
721 g_variant_unref(env);
722
723 ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(mock, obj, NULL));
724
725 /* Check for a multi-instance app */
726 ASSERT_TRUE(upstart_app_launch_start_application("multiple", NULL));
727
728 len = 0;
729 calls = dbus_test_dbus_mock_object_get_method_calls(mock, obj, "Start", &len, NULL);
730 EXPECT_NE(nullptr, calls);
731 EXPECT_EQ(1, len);
732
733 EXPECT_STREQ("Start", calls->name);
734 EXPECT_EQ(2, g_variant_n_children(calls->params));
735
736 block = g_variant_get_child_value(calls->params, 1);
737 EXPECT_TRUE(g_variant_get_boolean(block));
738 g_variant_unref(block);
739
740 env = g_variant_get_child_value(calls->params, 0);
741 EXPECT_TRUE(check_env(env, "APP_ID", "multiple"));
742 EXPECT_FALSE(check_env(env, "INSTANCE_ID", ""));
743 g_variant_unref(env);
744}
745
746static void
747failed_observer (const gchar * appid, upstart_app_launch_app_failed_t reason, gpointer user_data)
748{
749 if (reason == UPSTART_APP_LAUNCH_APP_FAILED_CRASH) {
750 std::string * last = static_cast<std::string *>(user_data);
751 *last = appid;
752 }
753 return;
754}
755
756TEST_F(LibUAL, FailingObserver)
757{
758 std::string last_observer;
759 GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
760
761 EXPECT_TRUE(upstart_app_launch_observer_add_app_failed(failed_observer, &last_observer));
762
763 g_dbus_connection_emit_signal(session,
764 NULL, /* destination */
765 "/", /* path */
766 "com.canonical.UpstartAppLaunch", /* interface */
767 "ApplicationFailed", /* signal */
768 g_variant_new("(ss)", "foo", "crash"), /* params, the same */
769 NULL);
770
771 pause(100);
772
773 EXPECT_EQ("foo", last_observer);
774
775 last_observer.clear();
776
777 g_dbus_connection_emit_signal(session,
778 NULL, /* destination */
779 "/", /* path */
780 "com.canonical.UpstartAppLaunch", /* interface */
781 "ApplicationFailed", /* signal */
782 g_variant_new("(ss)", "foo", "blahblah"), /* params, the same */
783 NULL);
784
785 pause(100);
786
787 EXPECT_EQ("foo", last_observer);
788
789 last_observer.clear();
790
791 g_dbus_connection_emit_signal(session,
792 NULL, /* destination */
793 "/", /* path */
794 "com.canonical.UpstartAppLaunch", /* interface */
795 "ApplicationFailed", /* signal */
796 g_variant_new("(ss)", "foo", "start-failure"), /* params, the same */
797 NULL);
798
799 pause(100);
800
801 EXPECT_TRUE(last_observer.empty());
802
803 EXPECT_TRUE(upstart_app_launch_observer_delete_app_failed(failed_observer, &last_observer));
804
805 g_object_unref(session);
806}
807
530808
=== added directory 'tests/link-farm'
=== added file 'tests/link-farm/README'
--- tests/link-farm/README 1970-01-01 00:00:00 +0000
+++ tests/link-farm/README 2014-02-11 03:28:22 +0000
@@ -0,0 +1,3 @@
1This directory is setup as our testing link farm. Anything that has a
2desktop in here will be detected as a click package, something without
3will be seen as a legacy package.
04
=== added file 'tests/link-farm/foo.desktop'
--- tests/link-farm/foo.desktop 1970-01-01 00:00:00 +0000
+++ tests/link-farm/foo.desktop 2014-02-11 03:28:22 +0000
@@ -0,0 +1,1 @@
1Needs to exist
02
=== added file 'tests/link-farm/foolike.desktop'
--- tests/link-farm/foolike.desktop 1970-01-01 00:00:00 +0000
+++ tests/link-farm/foolike.desktop 2014-02-11 03:28:22 +0000
@@ -0,0 +1,1 @@
1Needs to exist
02
=== modified file 'tests/manual'
--- tests/manual 2014-01-30 22:13:28 +0000
+++ tests/manual 2014-02-11 03:28:22 +0000
@@ -27,3 +27,10 @@
27 <dt>Send a URL to the service: <tt>upstart-app-launch ubuntu-system-settings settings:///system/battery</tt></dt>27 <dt>Send a URL to the service: <tt>upstart-app-launch ubuntu-system-settings settings:///system/battery</tt></dt>
28 <dd>The settings application should come back into focus and be on the power settings pane</dd>28 <dd>The settings application should come back into focus and be on the power settings pane</dd>
29</dl>29</dl>
30
31Test-case upstart-app-launch/security-app-launch
32<dl>
33 <dt>Setup the security tests: https://wiki.ubuntu.com/Touch/Testing#Running_Security_tests</dt>
34 <dt>Execute the <tt>click-apparmor</tt> test to start and stop several confined applications</dt>
35 <dd>Ensure that all applications start and stop correctly</dd>
36</dl>
3037
=== removed file 'tests/second-exec-test.cc'
--- tests/second-exec-test.cc 2013-12-06 11:44:25 +0000
+++ tests/second-exec-test.cc 1970-01-01 00:00:00 +0000
@@ -1,205 +0,0 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#include <gtest/gtest.h>
21#include <gio/gio.h>
22
23extern "C" {
24#include "../second-exec-core.h"
25#include "upstart-app-launch.h"
26#include "upstart-app-launch-mock.h"
27}
28
29class SecondExecTest : public ::testing::Test
30{
31 private:
32 GTestDBus * testbus = NULL;
33
34 protected:
35 std::string last_focus_appid;
36 std::string last_resume_appid;
37 guint resume_timeout = 0;
38
39 private:
40 static void focus_cb (const gchar * appid, gpointer user_data) {
41 SecondExecTest * _this = static_cast<SecondExecTest *>(user_data);
42 _this->last_focus_appid = appid;
43 }
44
45 static void resume_cb (const gchar * appid, gpointer user_data) {
46 SecondExecTest * _this = static_cast<SecondExecTest *>(user_data);
47 _this->last_resume_appid = appid;
48
49 if (_this->resume_timeout > 0) {
50 _this->pause(_this->resume_timeout);
51 }
52 }
53
54 protected:
55 virtual void SetUp() {
56 testbus = g_test_dbus_new(G_TEST_DBUS_NONE);
57 g_test_dbus_up(testbus);
58
59 upstart_app_launch_observer_add_app_focus(focus_cb, this);
60 upstart_app_launch_observer_add_app_resume(resume_cb, this);
61 }
62 virtual void TearDown() {
63 upstart_app_launch_observer_delete_app_focus(focus_cb, this);
64 upstart_app_launch_observer_delete_app_resume(resume_cb, this);
65
66 g_test_dbus_down(testbus);
67 g_object_unref(testbus);
68 }
69
70 static gboolean pause_helper (gpointer pmainloop) {
71 g_main_loop_quit((GMainLoop *)pmainloop);
72 return G_SOURCE_REMOVE;
73 }
74
75 void pause (guint time) {
76 if (time > 0) {
77 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
78 guint timer = g_timeout_add(time, pause_helper, mainloop);
79
80 g_main_loop_run(mainloop);
81
82 g_source_remove(timer);
83 g_main_loop_unref(mainloop);
84 }
85
86 while (g_main_pending()) {
87 g_main_iteration(TRUE);
88 }
89 }
90};
91
92TEST_F(SecondExecTest, AppIdTest)
93{
94 ASSERT_TRUE(second_exec("foo", NULL));
95 pause(50); /* Ensure all the events come through */
96 ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
97 ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
98}
99
100GDBusMessage *
101filter_func_good (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
102{
103 if (!incomming) {
104 return message;
105 }
106
107 if (g_strcmp0(g_dbus_message_get_path(message), (gchar *)user_data) == 0) {
108 GDBusMessage * reply = g_dbus_message_new_method_reply(message);
109 g_dbus_connection_send_message(conn, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
110 g_object_unref(message);
111 return NULL;
112 }
113
114 return message;
115}
116
117TEST_F(SecondExecTest, UrlSendTest)
118{
119 upstart_app_launch_mock_set_primary_pid(getpid());
120
121 GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
122 guint filter = g_dbus_connection_add_filter(session,
123 filter_func_good,
124 (gpointer)"/foo",
125 NULL);
126
127 ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
128 pause(100); /* Ensure all the events come through */
129
130 ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
131 ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
132
133 g_dbus_connection_remove_filter(session, filter);
134 g_object_unref(session);
135}
136
137TEST_F(SecondExecTest, UrlSendNoObjectTest)
138{
139 upstart_app_launch_mock_set_primary_pid(getpid());
140
141 ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
142 pause(100); /* Ensure all the events come through */
143
144 ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
145 ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
146}
147
148TEST_F(SecondExecTest, UnityTimeoutTest)
149{
150 this->resume_timeout = 100;
151
152 ASSERT_TRUE(second_exec("foo", NULL));
153 pause(100); /* Ensure all the events come through */
154 ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
155 ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
156}
157
158TEST_F(SecondExecTest, UnityTimeoutUriTest)
159{
160 this->resume_timeout = 200;
161
162 ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
163 pause(100); /* Ensure all the events come through */
164 ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
165 ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
166}
167
168GDBusMessage *
169filter_respawn (GDBusConnection * conn, GDBusMessage * message, gboolean incomming, gpointer user_data)
170{
171 if (g_strcmp0(g_dbus_message_get_member(message), "UnityResumeResponse") == 0) {
172 g_object_unref(message);
173 return NULL;
174 }
175
176 return message;
177}
178
179TEST_F(SecondExecTest, UnityLostTest)
180{
181 upstart_app_launch_mock_set_primary_pid(getpid());
182
183 GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
184 guint filter = g_dbus_connection_add_filter(session,
185 filter_respawn,
186 NULL,
187 NULL);
188
189 guint start = g_get_monotonic_time();
190
191 ASSERT_TRUE(second_exec("foo", "http://www.test.com"));
192
193 guint end = g_get_monotonic_time();
194
195 ASSERT_LT(end - start, 600 * 1000);
196
197 pause(100); /* Ensure all the events come through */
198 ASSERT_STREQ(this->last_focus_appid.c_str(), "foo");
199 ASSERT_STREQ(this->last_resume_appid.c_str(), "foo");
200
201 g_dbus_connection_remove_filter(session, filter);
202 g_object_unref(session);
203}
204
205
2060
=== modified file 'tests/zg-test.cc'
--- tests/zg-test.cc 2013-11-08 18:48:33 +0000
+++ tests/zg-test.cc 2014-02-11 03:28:22 +0000
@@ -66,3 +66,58 @@
66 g_object_unref(mock);66 g_object_unref(mock);
67 g_object_unref(service);67 g_object_unref(service);
68}68}
69
70static void
71zg_state_changed (DbusTestTask * task, DbusTestTaskState state, gpointer user_data)
72{
73 if (state != DBUS_TEST_TASK_STATE_FINISHED)
74 return;
75
76 g_debug("ZG Event Task Finished");
77
78 GMainLoop * mainloop = static_cast<GMainLoop *>(user_data);
79 g_main_loop_quit(mainloop);
80}
81
82TEST(ZGEvent, TimeoutTest)
83{
84 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
85 DbusTestService * service = dbus_test_service_new(NULL);
86
87 DbusTestDbusMock * mock = dbus_test_dbus_mock_new("org.gnome.zeitgeist.Engine");
88 DbusTestDbusMockObject * obj = dbus_test_dbus_mock_get_object(mock, "/org/gnome/zeitgeist/log/activity", "org.gnome.zeitgeist.Log", NULL);
89
90 dbus_test_dbus_mock_object_add_method(mock, obj,
91 "InsertEvents",
92 G_VARIANT_TYPE("a(asaasay)"),
93 G_VARIANT_TYPE("au"),
94 "time.sleep(6)\n"
95 "ret = [ 0 ]",
96 NULL);
97
98 dbus_test_service_add_task(service, DBUS_TEST_TASK(mock));
99
100 DbusTestProcess * zgevent = dbus_test_process_new(ZG_EVENT_TOOL);
101 dbus_test_process_append_param(zgevent, "close");
102 g_setenv("APP_ID", "foo", 1);
103 dbus_test_task_set_wait_for(DBUS_TEST_TASK(zgevent), "org.gnome.zeitgeist.Engine");
104 dbus_test_task_set_name(DBUS_TEST_TASK(zgevent), "ZGEvent");
105 g_signal_connect(G_OBJECT(zgevent), DBUS_TEST_TASK_SIGNAL_STATE_CHANGED, G_CALLBACK(zg_state_changed), mainloop);
106
107 dbus_test_service_add_task(service, DBUS_TEST_TASK(zgevent));
108
109 guint64 start = g_get_monotonic_time();
110
111 dbus_test_service_start_tasks(service);
112
113 g_main_loop_run(mainloop);
114
115 guint64 end = g_get_monotonic_time();
116
117 /* Four seconds to do a two second op -- ARM Jenkins is slow */
118 EXPECT_LT(end - start, 4 * 1000 * 1000);
119
120 g_object_unref(zgevent);
121 g_object_unref(service);
122 g_main_loop_unref(mainloop);
123}
69124
=== modified file 'upstart-app-watch.c'
--- upstart-app-watch.c 2013-12-05 17:14:55 +0000
+++ upstart-app-watch.c 2014-02-11 03:28:22 +0000
@@ -67,7 +67,7 @@
67 break;67 break;
68 }68 }
6969
70 g_print("Fail %s (%s)\n", appid, failstr);70 g_print("Fail %s (%s)\n", appid, failstr);
71 return;71 return;
72}72}
7373
7474
=== modified file 'zg-report-app.c'
--- zg-report-app.c 2013-11-08 18:17:42 +0000
+++ zg-report-app.c 2014-02-11 03:28:22 +0000
@@ -23,7 +23,7 @@
23static gboolean23static gboolean
24watchdog_timeout (gpointer user_data)24watchdog_timeout (gpointer user_data)
25{25{
26 g_error("Watchdog triggered, took too long to submit into Zeitgeist Database!");26 g_warning("Watchdog triggered, took too long to submit into Zeitgeist Database!");
27 g_main_loop_quit((GMainLoop *)user_data);27 g_main_loop_quit((GMainLoop *)user_data);
2828
29 return G_SOURCE_REMOVE;29 return G_SOURCE_REMOVE;
@@ -84,7 +84,7 @@
84 GMainLoop * main_loop = g_main_loop_new(NULL, FALSE);84 GMainLoop * main_loop = g_main_loop_new(NULL, FALSE);
8585
86 zeitgeist_log_insert_event(log, event, NULL, insert_complete, main_loop);86 zeitgeist_log_insert_event(log, event, NULL, insert_complete, main_loop);
87 g_timeout_add_seconds(4, watchdog_timeout, main_loop);87 g_timeout_add_seconds(2, watchdog_timeout, main_loop);
8888
89 g_main_loop_run(main_loop);89 g_main_loop_run(main_loop);
9090

Subscribers

People subscribed via source and target branches