Merge lp:~ted/ubuntu-app-launch/rm-rf-upstart into lp:ubuntu-app-launch

Proposed by Ted Gould
Status: Superseded
Proposed branch: lp:~ted/ubuntu-app-launch/rm-rf-upstart
Merge into: lp:ubuntu-app-launch
Diff against target: 7743 lines (+1211/-5115)
49 files modified
CMakeLists.txt (+1/-102)
application-failed.c (+0/-80)
application-job.c (+0/-113)
cgroup-reap-all.c (+0/-65)
debian/control (+0/-7)
exec-line-exec-trace.tp (+0/-19)
exec-line-exec.c (+0/-170)
libubuntu-app-launch/CMakeLists.txt (+1/-3)
libubuntu-app-launch/helper-impl-click.h (+0/-62)
libubuntu-app-launch/helper-impl.h (+78/-0)
libubuntu-app-launch/helper.cpp (+0/-36)
libubuntu-app-launch/helper.h (+6/-0)
libubuntu-app-launch/jobs-base.cpp (+255/-16)
libubuntu-app-launch/jobs-base.h (+47/-7)
libubuntu-app-launch/jobs-systemd.cpp (+13/-50)
libubuntu-app-launch/jobs-systemd.h (+9/-12)
libubuntu-app-launch/jobs-upstart.cpp (+0/-1211)
libubuntu-app-launch/jobs-upstart.h (+0/-101)
libubuntu-app-launch/registry.cpp (+28/-8)
libubuntu-app-launch/registry.h (+31/-0)
libubuntu-app-launch/ubuntu-app-launch.cpp (+217/-908)
tests/CMakeLists.txt (+3/-43)
tests/cgroup-reap-test.cc (+0/-145)
tests/exec-test-archcolon.sh (+0/-18)
tests/exec-test-colon.sh (+0/-18)
tests/exec-test-full.sh (+0/-18)
tests/exec-test-noarch.sh (+0/-18)
tests/exec-test-noinit.sh (+0/-18)
tests/exec-test-nullstr.sh (+0/-18)
tests/exec-test.sh.in (+0/-62)
tests/exec-util-test.cc (+0/-341)
tests/failure-test.cc (+0/-165)
tests/libual-cpp-test.cc (+163/-888)
tests/systemd-mock.h (+5/-0)
tests/zg-mock.h (+117/-0)
upstart-jobs/CMakeLists.txt (+0/-71)
upstart-jobs/application-click.conf.in (+0/-36)
upstart-jobs/application-failed.conf.in (+0/-6)
upstart-jobs/application-legacy.conf.in (+0/-36)
upstart-jobs/application-logrotate.conf (+0/-15)
upstart-jobs/application-snap.conf.in (+0/-37)
upstart-jobs/application.conf.in (+0/-17)
upstart-jobs/test-conffile.sh (+0/-12)
upstart-jobs/untrusted-helper-logrotate.conf (+0/-13)
upstart-jobs/untrusted-helper-type-end.conf.in (+0/-9)
upstart-jobs/untrusted-helper.conf.in (+0/-33)
utils/CMakeLists.txt (+55/-0)
utils/systemd-helper-helper.c (+182/-0)
zg-report-app.c (+0/-108)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/rm-rf-upstart
Reviewer Review Type Date Requested Status
Indicator Applet Developers Pending
Review via email: mp+317272@code.launchpad.net

This proposal has been superseded by a proposal from 2017-02-22.

Commit message

Remove Upstart

To post a comment you must log in.
295. By Ted Gould

Merge the jobs helper branch

296. By Ted Gould

Remove the untrusted helper type util

297. By Ted Gould

Test location updates

298. By Ted Gould

Update to future trunk

299. By Ted Gould

Update to jobs helpers

300. By Ted Gould

Grabbing the jobs-helper updates

301. By Ted Gould

Demangler support

302. By Ted Gould

Remove upstart dirs and make sure we have a dbus-user-session

303. By Ted Gould

Merge future trunk

304. By Ted Gould

Remove a few upstart headers

305. By Ted Gould

Remove old environment variable helpers

306. By Ted Gould

Drop CG Manager variables

307. By Ted Gould

Grab upstream fixes

308. By Ted Gould

Remove Upstart objects from docs

309. By Ted Gould

Merge updated jobs-helpers

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2017-01-26 20:05:22 +0000
3+++ CMakeLists.txt 2017-02-22 21:41:30 +0000
4@@ -79,9 +79,6 @@
5 pkg_check_modules(CLICK REQUIRED click-0.4>=0.4.18)
6 include_directories(${CLICK_INCLUDE_DIRS})
7
8-pkg_check_modules(LIBUPSTART REQUIRED libupstart)
9-include_directories(${LIBUPSTART_INCLUDE_DIRS})
10-
11 pkg_check_modules(DBUS REQUIRED dbus-1)
12 include_directories(${DBUS_INCLUDE_DIRS})
13
14@@ -130,70 +127,6 @@
15 install(TARGETS desktop-hook RUNTIME DESTINATION "${pkglibexecdir}")
16
17 ####################
18-# exec-line-exec
19-####################
20-
21-add_lttng_gen_tp(NAME exec-line-exec-trace)
22-include_directories(${CMAKE_CURRENT_BINARY_DIR})
23-add_executable(exec-line-exec exec-line-exec.c "${CMAKE_CURRENT_BINARY_DIR}/exec-line-exec-trace.c")
24-set_target_properties(exec-line-exec PROPERTIES OUTPUT_NAME "exec-line-exec")
25-target_link_libraries(exec-line-exec helpers ${LTTNG_LIBRARIES})
26-install(TARGETS exec-line-exec RUNTIME DESTINATION "${pkglibexecdir}")
27-
28-####################
29-# zg-report-app
30-####################
31-
32-add_executable(zg-report-app zg-report-app.c)
33-set_target_properties(zg-report-app PROPERTIES OUTPUT_NAME "zg-report-app")
34-target_link_libraries(zg-report-app ubuntu-launcher ${ZEITGEIST_LIBRARIES} ${GOBJECT2_LIBRARIES} ${GLIB2_LIBRARIES})
35-install(TARGETS zg-report-app RUNTIME DESTINATION "${pkglibexecdir}")
36-
37-####################
38-# application-job
39-####################
40-
41-add_executable(application-job application-job.c)
42-set_target_properties(application-job PROPERTIES OUTPUT_NAME "application-job")
43-target_link_libraries(application-job ubuntu-launcher)
44-install(TARGETS application-job RUNTIME DESTINATION "${pkglibexecdir}")
45-
46-####################
47-# application-failed
48-####################
49-
50-add_executable(application-failed application-failed.c)
51-set_target_properties(application-failed PROPERTIES OUTPUT_NAME "application-failed")
52-target_link_libraries(application-failed ${GIO2_LIBRARIES})
53-install(TARGETS application-failed RUNTIME DESTINATION "${pkglibexecdir}")
54-
55-####################
56-# xmir-helper
57-####################
58-
59-add_executable(xmir-helper xmir-helper.c)
60-set_target_properties(xmir-helper PROPERTIES OUTPUT_NAME "xmir-helper")
61-install(TARGETS xmir-helper RUNTIME DESTINATION "${pkglibexecdir}")
62-
63-####################
64-# untrusted-helper-type-end
65-####################
66-
67-add_executable(untrusted-helper-type-end untrusted-helper-type-end.c)
68-set_target_properties(untrusted-helper-type-end PROPERTIES OUTPUT_NAME "untrusted-helper-type-end")
69-target_link_libraries(untrusted-helper-type-end ubuntu-launcher)
70-install(TARGETS untrusted-helper-type-end RUNTIME DESTINATION "${pkglibexecdir}")
71-
72-####################
73-# cgroup-reap-all
74-####################
75-
76-add_executable(cgroup-reap-all cgroup-reap-all.c)
77-set_target_properties(cgroup-reap-all PROPERTIES OUTPUT_NAME "cgroup-reap-all")
78-target_link_libraries(cgroup-reap-all helpers)
79-install(TARGETS cgroup-reap-all RUNTIME DESTINATION "${pkglibexecdir}")
80-
81-####################
82 # oom-adjust-setuid-helper
83 ####################
84
85@@ -202,48 +135,15 @@
86 install(TARGETS oom-adjust-setuid-helper RUNTIME DESTINATION "${pkglibexecdir}")
87
88 ####################
89-# socket-demangler
90-####################
91-
92-add_executable(socket-demangler-helper socket-demangler.c)
93-set_target_properties(socket-demangler-helper PROPERTIES OUTPUT_NAME "socket-demangler")
94-target_link_libraries(socket-demangler-helper ${GIO2_LIBRARIES})
95-install(TARGETS socket-demangler-helper RUNTIME DESTINATION "${pkglibexecdir}")
96-
97-####################
98-# snappy-xmir
99-####################
100-
101-####################
102-# NOTE: This only can link to libraries that are in
103-# the base UBUNTU CORE image. Which is basically libc
104-# and not much else. Don't add libs.
105-####################
106-
107-add_executable(snappy-xmir snappy-xmir.c)
108-set_target_properties(snappy-xmir PROPERTIES OUTPUT_NAME "snappy-xmir")
109-install(TARGETS snappy-xmir RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}")
110-
111-####################
112-# snappy-xmir-envvars
113-####################
114-
115-add_executable(snappy-xmir-envvars snappy-xmir-envvars.c)
116-set_target_properties(snappy-xmir-envvars PROPERTIES OUTPUT_NAME "snappy-xmir-envvars")
117-# No libs, otherwise we have to worry about how to handle finding them
118-install(TARGETS snappy-xmir-envvars RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}")
119-
120-
121-####################
122 # ubuntu-app-launch-desktop.click-hook
123 ####################
124
125 configure_file("ubuntu-app-launch-desktop.click-hook.in" "${CMAKE_CURRENT_SOURCE_DIR}/debian/ubuntu-app-launch-desktop.click-hook" @ONLY)
126
127 add_subdirectory(libubuntu-app-launch)
128-add_subdirectory(upstart-jobs)
129 add_subdirectory(tools)
130 add_subdirectory(ubuntu-app-test)
131+add_subdirectory(utils)
132
133 # testing & coverage
134 if (${enable_tests})
135@@ -265,7 +165,6 @@
136 TESTS
137 application-icon-finder-test
138 application-info-desktop-test
139- cgroup-reap-test
140 exec-util-test
141 failure-test
142 helper-test
143
144=== removed file 'application-failed.c'
145--- application-failed.c 2016-12-14 21:11:09 +0000
146+++ application-failed.c 1970-01-01 00:00:00 +0000
147@@ -1,80 +0,0 @@
148-
149-/*
150- * Copyright 2013 Canonical Ltd.
151- *
152- * This program is free software: you can redistribute it and/or modify it
153- * under the terms of the GNU General Public License version 3, as published
154- * by the Free Software Foundation.
155- *
156- * This program is distributed in the hope that it will be useful, but
157- * WITHOUT ANY WARRANTY; without even the implied warranties of
158- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
159- * PURPOSE. See the GNU General Public License for more details.
160- *
161- * You should have received a copy of the GNU General Public License along
162- * with this program. If not, see <http://www.gnu.org/licenses/>.
163- *
164- * Authors:
165- * Ted Gould <ted.gould@canonical.com>
166- */
167-
168-#include <gio/gio.h>
169-
170-int
171-main (int argc, char * argv[])
172-{
173- const gchar * job = g_getenv("JOB");
174- g_return_val_if_fail(job != NULL, -1);
175-
176- const gchar * instance = g_getenv("INSTANCE");
177- g_return_val_if_fail(instance != NULL, -1);
178-
179- gboolean crashed = FALSE;
180- if (g_getenv("EXIT_STATUS") != NULL || g_getenv("EXIT_SIGNAL") != NULL) {
181- crashed = TRUE;
182- }
183-
184- gchar * appid = g_strdup(instance);
185- gchar * lasthyphenstanding = NULL;
186- if (g_strcmp0(job, "application-legacy") == 0
187- || g_strcmp0(job, "application-snap") == 0) {
188- lasthyphenstanding = g_strrstr(appid, "-");
189- if (lasthyphenstanding != NULL) {
190- lasthyphenstanding[0] = '\0';
191- } else {
192- g_warning("Legacy job instance '%s' is missing a hyphen", appid);
193- }
194- }
195-
196- if (lasthyphenstanding == NULL) {
197- lasthyphenstanding = "";
198- } else {
199- lasthyphenstanding++;
200- }
201-
202- GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
203- g_return_val_if_fail(bus != NULL, -1);
204-
205- GError * error = NULL;
206- g_dbus_connection_emit_signal(bus,
207- NULL, /* destination */
208- "/", /* path */
209- "com.canonical.UbuntuAppLaunch",
210- "ApplicationFailed",
211- g_variant_new("(sss)", appid, lasthyphenstanding, crashed ? "crash" : "start-failure"),
212- &error);
213-
214- g_debug("Emitting failed event '%s' for app '%s'", crashed ? "crash" : "start-failure", appid);
215-
216- if (error != NULL) {
217- g_warning("Unable to emit signal: %s", error->message);
218- g_error_free(error);
219- return -1;
220- }
221-
222- g_dbus_connection_flush_sync(bus, NULL, NULL);
223- g_object_unref(bus);
224- g_free(appid);
225-
226- return 0;
227-}
228
229=== removed file 'application-job.c'
230--- application-job.c 2014-04-30 16:34:06 +0000
231+++ application-job.c 1970-01-01 00:00:00 +0000
232@@ -1,113 +0,0 @@
233-/*
234- * Copyright 2013 Canonical Ltd.
235- *
236- * This program is free software: you can redistribute it and/or modify it
237- * under the terms of the GNU General Public License version 3, as published
238- * by the Free Software Foundation.
239- *
240- * This program is distributed in the hope that it will be useful, but
241- * WITHOUT ANY WARRANTY; without even the implied warranties of
242- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
243- * PURPOSE. See the GNU General Public License for more details.
244- *
245- * You should have received a copy of the GNU General Public License along
246- * with this program. If not, see <http://www.gnu.org/licenses/>.
247- *
248- * Authors:
249- * Ted Gould <ted.gould@canonical.com>
250- */
251-
252-#include <gio/gio.h>
253-#include "libubuntu-app-launch/ubuntu-app-launch.h"
254-
255-int retval = 0;
256-const gchar * global_appid;
257-
258-static void
259-app_started (const gchar * appid, gpointer user_data)
260-{
261- if (g_strcmp0(appid, global_appid) != 0)
262- return;
263- g_debug("Application Started: %s", appid);
264- g_main_loop_quit((GMainLoop *)user_data);
265-}
266-
267-static void
268-app_focus (const gchar * appid, gpointer user_data)
269-{
270- if (g_strcmp0(appid, global_appid) != 0)
271- return;
272- g_debug("Application Focused");
273- g_main_loop_quit((GMainLoop *)user_data);
274-}
275-
276-static void
277-app_failed (const gchar * appid, UbuntuAppLaunchAppFailed failure_type, gpointer user_data)
278-{
279- if (g_strcmp0(appid, global_appid) != 0)
280- return;
281- g_warning("Application Startup Failed");
282- retval = 1;
283- g_main_loop_quit((GMainLoop *)user_data);
284-}
285-
286-/* A fallback so that we can see what is going on. The job can not always signal
287- that it has been started, and thus we wouldn't quit. Which would be a bad thing. */
288-static gboolean
289-timeout_check (gpointer user_data)
290-{
291- g_debug("Timeout reached");
292- g_main_loop_quit((GMainLoop *)user_data);
293- return TRUE; /* Keep the source connected to avoid the disconnect error */
294-}
295-
296-int
297-main (int argc, char * argv[])
298-{
299- GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
300- g_return_val_if_fail(con != NULL, 1);
301-
302- global_appid = g_getenv("APP_ID");
303- g_return_val_if_fail(global_appid != NULL, 1);
304-
305- const gchar * uris_str = g_getenv("APP_URIS");
306- gchar ** uris = NULL;
307- if (uris_str != NULL) {
308- GError * error = NULL;
309- gint uri_count = 0;
310- g_shell_parse_argv(uris_str, &uri_count, &uris, &error);
311-
312- if (error != NULL) {
313- g_warning("Unable to parse uris '%s': %s", uris_str, error->message);
314- g_error_free(error);
315- } else {
316- g_debug("Got %d URIs", uri_count);
317- }
318- }
319-
320- GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
321-
322- ubuntu_app_launch_observer_add_app_started(app_started, mainloop);
323- ubuntu_app_launch_observer_add_app_focus(app_focus, mainloop);
324- ubuntu_app_launch_observer_add_app_failed(app_failed, mainloop);
325-
326- guint timer = g_timeout_add_seconds(1, timeout_check, mainloop);
327-
328- g_debug("Start Application: %s", global_appid);
329- g_return_val_if_fail(ubuntu_app_launch_start_application(global_appid, (const gchar * const *)uris), -1);
330- g_strfreev(uris);
331-
332- g_debug("Wait for results");
333- g_main_loop_run(mainloop);
334-
335- g_source_remove(timer);
336-
337- ubuntu_app_launch_observer_delete_app_started(app_started, mainloop);
338- ubuntu_app_launch_observer_delete_app_focus(app_focus, mainloop);
339- ubuntu_app_launch_observer_delete_app_failed(app_failed, mainloop);
340-
341- g_main_loop_unref(mainloop);
342- g_object_unref(con);
343-
344- return retval;
345-}
346
347=== removed file 'cgroup-reap-all.c'
348--- cgroup-reap-all.c 2014-11-20 20:33:59 +0000
349+++ cgroup-reap-all.c 1970-01-01 00:00:00 +0000
350@@ -1,65 +0,0 @@
351-/*
352- * Copyright © 2014 Canonical Ltd.
353- *
354- * This program is free software: you can redistribute it and/or modify it
355- * under the terms of the GNU General Public License version 3, as published
356- * by the Free Software Foundation.
357- *
358- * This program is distributed in the hope that it will be useful, but
359- * WITHOUT ANY WARRANTY; without even the implied warranties of
360- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
361- * PURPOSE. See the GNU General Public License for more details.
362- *
363- * You should have received a copy of the GNU General Public License along
364- * with this program. If not, see <http://www.gnu.org/licenses/>.
365- *
366- * Authors:
367- * Ted Gould <ted.gould@canonical.com>
368- */
369-
370-#include "helpers.h"
371-
372-int kill (pid_t pid, int signal);
373-pid_t getpgid (pid_t);
374-
375-int
376-main (int argc, char * argv[])
377-{
378- /* Break off a new process group */
379- setpgid(0, 0);
380-
381- GDBusConnection * cgmanager = cgroup_manager_connection();
382- g_return_val_if_fail(cgmanager != NULL, -1);
383-
384- GPid selfpid = getpid();
385- GPid parentpid = getppid();
386-
387- /* We're gonna try to kill things forever, literally. It's important
388- enough that we can't consider failure an option. */
389- gboolean killed = TRUE;
390- while (killed) {
391- GList * pidlist = pids_from_cgroup(cgmanager, NULL, NULL);
392- GList * head;
393-
394- killed = FALSE;
395-
396- for (head = pidlist; head != NULL; head = g_list_next(head)) {
397- GPid pid = GPOINTER_TO_INT(head->data);
398-
399- /* We don't want to kill ourselves, or if we're being executed by
400- a script, that script, either. We also don't want things in our
401- process group which we forked at the opening */
402- if (pid != selfpid && pid != parentpid && getpgid(pid) != selfpid) {
403- g_debug("Killing pid: %d", pid);
404- kill(pid, SIGKILL);
405- killed = TRUE;
406- }
407- }
408-
409- g_list_free(pidlist);
410- }
411-
412- cgroup_manager_unref(cgmanager);
413-
414- return 0;
415-}
416
417=== modified file 'debian/control'
418--- debian/control 2017-01-19 18:39:44 +0000
419+++ debian/control 2017-02-22 21:41:30 +0000
420@@ -22,18 +22,14 @@
421 liblibertine-dev,
422 liblttng-ust-dev,
423 libmirclient-dev (>= 0.5),
424- libnih-dbus-dev,
425- libnih-dev,
426 libproperties-cpp-dev,
427 # For ABI check to distro version
428 # Make sure to set DEB_BUILD_PROFILES when bootstrapping
429 libubuntu-app-launch2-dev <!stage1>,
430- libupstart-dev,
431 libwhoopsie-dev (>= 0.2.52),
432 libzeitgeist-2.0-dev,
433 gobject-introspection,
434 python3-dbusmock,
435- upstart (>= 1.13),
436 Standards-Version: 3.9.4
437 Homepage: http://launchpad.net/ubuntu-app-launch
438 # If you aren't a member of ~indicator-applet-developers but need to upload packaging changes,
439@@ -45,10 +41,7 @@
440 Architecture: any
441 Depends: ${shlibs:Depends},
442 ${misc:Depends},
443- cgmanager,
444 click-apparmor,
445- libpam-cgfs | libpam-cgm | cgmanager (<< 0.37),
446- upstart (>= 1.13),
447 xmir [amd64 armhf i386],
448 zeitgeist-core,
449 Replaces: upstart-app-launch
450
451=== removed file 'exec-line-exec-trace.tp'
452--- exec-line-exec-trace.tp 2014-09-17 14:11:59 +0000
453+++ exec-line-exec-trace.tp 1970-01-01 00:00:00 +0000
454@@ -1,19 +0,0 @@
455-
456-TRACEPOINT_EVENT(ubuntu_app_launch, exec_start,
457- TP_ARGS(const char *, appid),
458- TP_FIELDS(
459- ctf_string(appid, appid)
460- )
461-)
462-TRACEPOINT_EVENT(ubuntu_app_launch, exec_parse_complete,
463- TP_ARGS(const char *, appid),
464- TP_FIELDS(
465- ctf_string(appid, appid)
466- )
467-)
468-TRACEPOINT_EVENT(ubuntu_app_launch, exec_pre_exec,
469- TP_ARGS(const char *, appid),
470- TP_FIELDS(
471- ctf_string(appid, appid)
472- )
473-)
474
475=== removed file 'exec-line-exec.c'
476--- exec-line-exec.c 2015-06-30 20:42:24 +0000
477+++ exec-line-exec.c 1970-01-01 00:00:00 +0000
478@@ -1,170 +0,0 @@
479-/*
480- * Copyright 2013 Canonical Ltd.
481- *
482- * This program is free software: you can redistribute it and/or modify it
483- * under the terms of the GNU General Public License version 3, as published
484- * by the Free Software Foundation.
485- *
486- * This program is distributed in the hope that it will be useful, but
487- * WITHOUT ANY WARRANTY; without even the implied warranties of
488- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
489- * PURPOSE. See the GNU General Public License for more details.
490- *
491- * You should have received a copy of the GNU General Public License along
492- * with this program. If not, see <http://www.gnu.org/licenses/>.
493- *
494- * Authors:
495- * Ted Gould <ted.gould@canonical.com>
496- */
497-
498-#include <unistd.h>
499-#include <errno.h>
500-#include <string.h>
501-
502-#include <glib.h>
503-#include <glib/gstdio.h>
504-
505-#include "exec-line-exec-trace.h"
506-#include "helpers.h"
507-#include "ual-tracepoint.h"
508-
509-int
510-main (int argc, char * argv[])
511-{
512- /* Make sure we have work to do */
513- /* This string is quoted using desktop file quoting:
514- http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables */
515- const gchar * app_exec = g_getenv("APP_EXEC");
516- if (app_exec == NULL) {
517- /* There should be no reason for this, a g_error() so that it gets
518- picked up by Apport and we can track it */
519- g_error("No exec line given, nothing to do except fail");
520- return 1;
521- }
522-
523- /* For the tracepoints */
524- const gchar * app_id = g_getenv("APP_ID");
525-
526- ual_tracepoint(exec_start, app_id);
527-
528- /* URIs */
529- const gchar * app_uris = g_getenv("APP_URIS");
530-
531- /* Look to see if we have a directory defined that we
532- should be using for everything. If so, change to it
533- and add it to the path */
534- const gchar * appdir = g_getenv("APP_DIR");
535-
536- if (appdir != NULL) {
537- if (g_chdir(appdir) != 0) {
538- g_warning("Unable to change directory to '%s'", appdir);
539- }
540- }
541-
542- /* Protect against app directories that have ':' in them */
543- if (appdir != NULL && strchr(appdir, ':') == NULL) {
544- const gchar * path_path = g_getenv("PATH");
545- if (path_path != NULL && path_path[0] == '\0')
546- path_path = NULL;
547- gchar * path_libpath = NULL;
548- const gchar * path_joinable[4] = { 0 };
549-
550- const gchar * lib_path = g_getenv("LD_LIBRARY_PATH");
551- if (lib_path != NULL && lib_path[0] == '\0')
552- lib_path = NULL;
553- gchar * lib_libpath = g_build_filename(appdir, "lib", NULL);
554- const gchar * lib_joinable[4] = { 0 };
555-
556- const gchar * import_path = g_getenv("QML2_IMPORT_PATH");
557- if (import_path != NULL && import_path[0] == '\0')
558- import_path = NULL;
559- gchar * import_libpath = NULL;
560- const gchar * import_joinable[4] = { 0 };
561-
562- /* If we've got an architecture set insert that into the
563- path before everything else */
564- const gchar * archdir = g_getenv("UBUNTU_APP_LAUNCH_ARCH");
565- if (archdir != NULL && strchr(archdir, ':') == NULL) {
566- path_libpath = g_build_filename(appdir, "lib", archdir, "bin", NULL);
567- import_libpath = g_build_filename(appdir, "lib", archdir, NULL);
568-
569- path_joinable[0] = path_libpath;
570- path_joinable[1] = appdir;
571- path_joinable[2] = path_path;
572-
573- lib_joinable[0] = import_libpath;
574- lib_joinable[1] = lib_libpath;
575- lib_joinable[2] = lib_path;
576-
577- /* Need to check whether the original is NULL because we're
578- appending instead of prepending */
579- if (import_path == NULL) {
580- import_joinable[0] = import_libpath;
581- } else {
582- import_joinable[0] = import_path;
583- import_joinable[1] = import_libpath;
584- }
585- } else {
586- path_joinable[0] = appdir;
587- path_joinable[1] = path_path;
588-
589- lib_joinable[0] = lib_libpath;
590- lib_joinable[1] = lib_path;
591-
592- import_joinable[0] = import_path;
593- }
594-
595- gchar * newpath = g_strjoinv(":", (gchar**)path_joinable);
596- g_setenv("PATH", newpath, TRUE);
597- g_free(path_libpath);
598- g_free(newpath);
599-
600- gchar * newlib = g_strjoinv(":", (gchar**)lib_joinable);
601- g_setenv("LD_LIBRARY_PATH", newlib, TRUE);
602- g_free(lib_libpath);
603- g_free(newlib);
604-
605- if (import_joinable[0] != NULL) {
606- gchar * newimport = g_strjoinv(":", (gchar**)import_joinable);
607- g_setenv("QML2_IMPORT_PATH", newimport, TRUE);
608- g_free(newimport);
609- }
610- g_free(import_libpath);
611- }
612-
613- /* Parse the execiness of it all */
614- GArray * newargv = desktop_exec_parse(app_exec, app_uris);
615- if (newargv == NULL) {
616- g_warning("Unable to parse exec line '%s'", app_exec);
617- return 1;
618- }
619-
620- ual_tracepoint(exec_parse_complete, app_id);
621-
622- if (g_getenv("MIR_SOCKET") != NULL && g_strcmp0(g_getenv("APP_XMIR_ENABLE"), "1") == 0) {
623- g_debug("XMir Helper being used");
624-
625- /* xmir-helper $(APP_ID) $(COMMAND) */
626- const gchar * appid = g_getenv("APP_ID");
627- g_array_prepend_val(newargv, appid);
628-
629- /* Pulling into the heap instead of the code page */
630- char * xmir_helper = g_strdup(XMIR_HELPER);
631- g_array_prepend_val(newargv, xmir_helper);
632- }
633-
634- /* Now exec */
635- gchar ** nargv = (gchar**)g_array_free(newargv, FALSE);
636-
637- ual_tracepoint(exec_pre_exec, app_id);
638-
639- int execret = execvp(nargv[0], nargv);
640-
641- if (execret != 0) {
642- gchar * execprint = g_strjoinv(" ", nargv);
643- g_warning("Unable to exec '%s' in '%s': %s", execprint, appdir, strerror(errno));
644- g_free(execprint);
645- }
646-
647- return execret;
648-}
649
650=== modified file 'libubuntu-app-launch/CMakeLists.txt'
651--- libubuntu-app-launch/CMakeLists.txt 2016-11-17 16:58:26 +0000
652+++ libubuntu-app-launch/CMakeLists.txt 2017-02-22 21:41:30 +0000
653@@ -36,6 +36,7 @@
654 set(LAUNCHER_CPP_SOURCES
655 application.cpp
656 helper.cpp
657+helper-impl.h
658 registry.cpp
659 registry-impl.h
660 registry-impl.cpp
661@@ -51,15 +52,12 @@
662 application-info-desktop.cpp
663 application-icon-finder.h
664 application-icon-finder.cpp
665-helper-impl-click.cpp
666 glib-thread.h
667 glib-thread.cpp
668 jobs-base.h
669 jobs-base.cpp
670 jobs-systemd.h
671 jobs-systemd.cpp
672-jobs-upstart.h
673-jobs-upstart.cpp
674 )
675
676 set(LAUNCHER_SOURCES
677
678=== removed file 'libubuntu-app-launch/helper-impl-click.h'
679--- libubuntu-app-launch/helper-impl-click.h 2016-06-09 14:55:34 +0000
680+++ libubuntu-app-launch/helper-impl-click.h 1970-01-01 00:00:00 +0000
681@@ -1,62 +0,0 @@
682-/*
683- * Copyright © 2016 Canonical Ltd.
684- *
685- * This program is free software: you can redistribute it and/or modify it
686- * under the terms of the GNU General Public License version 3, as published
687- * by the Free Software Foundation.
688- *
689- * This program is distributed in the hope that it will be useful, but
690- * WITHOUT ANY WARRANTY; without even the implied warranties of
691- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
692- * PURPOSE. See the GNU General Public License for more details.
693- *
694- * You should have received a copy of the GNU General Public License along
695- * with this program. If not, see <http://www.gnu.org/licenses/>.
696- *
697- * Authors:
698- * Ted Gould <ted.gould@canonical.com>
699- */
700-
701-#include <list>
702-
703-#include "helper.h"
704-
705-namespace ubuntu
706-{
707-namespace app_launch
708-{
709-namespace helper_impls
710-{
711-
712-class Click : public Helper
713-{
714-public:
715- Click(const Helper::Type& type, const AppID& appid, const std::shared_ptr<Registry>& registry)
716- : _type(type)
717- , _appid(appid)
718- , _registry(registry)
719- {
720- }
721-
722- AppID appId() override
723- {
724- return _appid;
725- }
726-
727- bool hasInstances() override;
728- std::vector<std::shared_ptr<Helper::Instance>> instances() override;
729-
730- std::shared_ptr<Helper::Instance> launch(std::vector<Helper::URL> urls = {}) override;
731- std::shared_ptr<Helper::Instance> launch(MirPromptSession* session, std::vector<Helper::URL> urls = {}) override;
732-
733- static std::list<std::shared_ptr<Helper>> running(Helper::Type type, std::shared_ptr<Registry> registry);
734-
735-private:
736- Helper::Type _type;
737- AppID _appid;
738- std::shared_ptr<Registry> _registry;
739-};
740-
741-} // namespace helper_impl
742-} // namespace app_launch
743-} // namespace ubuntu
744
745=== added file 'libubuntu-app-launch/helper-impl.h'
746--- libubuntu-app-launch/helper-impl.h 1970-01-01 00:00:00 +0000
747+++ libubuntu-app-launch/helper-impl.h 2017-02-22 21:41:30 +0000
748@@ -0,0 +1,78 @@
749+/*
750+ * Copyright © 2017 Canonical Ltd.
751+ *
752+ * This program is free software: you can redistribute it and/or modify it
753+ * under the terms of the GNU General Public License version 3, as published
754+ * by the Free Software Foundation.
755+ *
756+ * This program is distributed in the hope that it will be useful, but
757+ * WITHOUT ANY WARRANTY; without even the implied warranties of
758+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
759+ * PURPOSE. See the GNU General Public License for more details.
760+ *
761+ * You should have received a copy of the GNU General Public License along
762+ * with this program. If not, see <http://www.gnu.org/licenses/>.
763+ *
764+ * Authors:
765+ * Ted Gould <ted.gould@canonical.com>
766+ */
767+
768+#pragma once
769+
770+#include <list>
771+
772+#include "helper.h"
773+#include "jobs-base.h"
774+
775+namespace ubuntu
776+{
777+namespace app_launch
778+{
779+namespace helper_impls
780+{
781+
782+/** We really should have put a relationship between Helper::Instance
783+and Application::Instance in the API. But to work around that today
784+we're just handling it here because the helper interface is a subset
785+of what the Application::Instance class provides */
786+class BaseInstance : public Helper::Instance
787+{
788+public:
789+ std::shared_ptr<jobs::instance::Base> impl;
790+
791+ BaseInstance(const std::shared_ptr<jobs::instance::Base>& inst);
792+ BaseInstance(const std::shared_ptr<Application::Instance>& inst);
793+
794+ bool isRunning() override;
795+ void stop() override;
796+
797+ const std::string& getInstanceId()
798+ {
799+ return impl->getInstanceId();
800+ }
801+};
802+
803+class Base : public Helper
804+{
805+public:
806+ Base(const Helper::Type& type, const AppID& appid, const std::shared_ptr<Registry>& registry);
807+
808+ AppID appId() override;
809+
810+ bool hasInstances() override;
811+ std::vector<std::shared_ptr<Helper::Instance>> instances() override;
812+
813+ std::shared_ptr<Helper::Instance> launch(std::vector<Helper::URL> urls = {}) override;
814+ std::shared_ptr<Helper::Instance> launch(MirPromptSession* session, std::vector<Helper::URL> urls = {}) override;
815+
816+ std::shared_ptr<Helper::Instance> existingInstance(const std::string& instanceid);
817+
818+private:
819+ Helper::Type _type;
820+ AppID _appid;
821+ std::shared_ptr<Registry> _registry;
822+};
823+
824+} // namespace helper_impl
825+} // namespace app_launch
826+} // namespace ubuntu
827
828=== renamed file 'libubuntu-app-launch/helper-impl-click.cpp' => 'libubuntu-app-launch/helper.cpp'
829--- libubuntu-app-launch/helper-impl-click.cpp 2016-06-09 14:55:34 +0000
830+++ libubuntu-app-launch/helper.cpp 2017-02-22 21:41:30 +0000
831@@ -1,5 +1,5 @@
832 /*
833- * Copyright © 2016 Canonical Ltd.
834+ * Copyright © 2016-2017 Canonical Ltd.
835 *
836 * This program is free software: you can redistribute it and/or modify it
837 * under the terms of the GNU General Public License version 3, as published
838@@ -17,11 +17,19 @@
839 * Ted Gould <ted.gould@canonical.com>
840 */
841
842-#include "helper-impl-click.h"
843+#include <algorithm>
844+#include <list>
845+
846+#include "helper-impl.h"
847 #include "registry-impl.h"
848
849 #include "ubuntu-app-launch.h"
850
851+extern "C" {
852+#include "proxy-socket-demangler.h"
853+#include <gio/gunixfdlist.h>
854+}
855+
856 namespace ubuntu
857 {
858 namespace app_launch
859@@ -29,148 +37,296 @@
860 namespace helper_impls
861 {
862
863-bool Click::hasInstances()
864-{
865- return _registry->impl->thread.executeOnThread<bool>([this]() {
866- auto instances = ubuntu_app_launch_list_helper_instances(_type.value().c_str(), ((std::string)_appid).c_str());
867- auto retval = (g_strv_length(instances) != 0);
868-
869- g_strfreev(instances);
870-
871- return retval;
872- });
873-}
874-
875-class ClickInstance : public Helper::Instance
876-{
877-public: /* all one file, no one to hide from */
878- AppID _appid;
879- Helper::Type _type;
880- std::string _instanceid;
881- std::shared_ptr<Registry> _registry;
882-
883- ClickInstance(const AppID& appid,
884- const Helper::Type& type,
885- const std::string& instanceid,
886- std::shared_ptr<Registry> registry)
887- : _appid(appid)
888- , _type(type)
889- , _instanceid(instanceid)
890- , _registry(registry)
891- {
892- }
893-
894- bool isRunning() override
895- {
896- return _registry->impl->thread.executeOnThread<bool>([this]() {
897- bool found = false;
898-
899- auto instances =
900- ubuntu_app_launch_list_helper_instances(_type.value().c_str(), ((std::string)_appid).c_str());
901- for (int i = 0; instances[i] != nullptr; i++)
902- {
903- if (_instanceid == std::string(instances[i]))
904+/**********************
905+ * Instance
906+ **********************/
907+
908+BaseInstance::BaseInstance(const std::shared_ptr<jobs::instance::Base>& inst)
909+ : impl{inst}
910+{
911+}
912+
913+BaseInstance::BaseInstance(const std::shared_ptr<Application::Instance>& inst)
914+ : impl{std::dynamic_pointer_cast<jobs::instance::Base>(inst)}
915+{
916+}
917+
918+bool BaseInstance::isRunning()
919+{
920+ return impl->isRunning();
921+}
922+
923+void BaseInstance::stop()
924+{
925+ impl->stop();
926+}
927+
928+/**********************
929+ * Helper Class
930+ **********************/
931+
932+Base::Base(const Helper::Type& type, const AppID& appid, const std::shared_ptr<Registry>& registry)
933+ : _type(type)
934+ , _appid(appid)
935+ , _registry(registry)
936+{
937+}
938+
939+AppID Base::appId()
940+{
941+ return _appid;
942+}
943+
944+bool Base::hasInstances()
945+{
946+ return instances().size() > 0;
947+}
948+
949+std::vector<std::shared_ptr<Helper::Instance>> Base::instances()
950+{
951+ auto insts = _registry->impl->jobs->instances(_appid, _type.value());
952+ std::vector<std::shared_ptr<Helper::Instance>> wrapped;
953+
954+ std::transform(insts.begin(), insts.end(), wrapped.begin(),
955+ [](std::shared_ptr<jobs::instance::Base>& inst) { return std::make_shared<BaseInstance>(inst); });
956+
957+ return wrapped;
958+}
959+
960+/** Find an instance that we already know the ID of */
961+std::shared_ptr<Helper::Instance> Base::existingInstance(const std::string& instanceid)
962+{
963+ auto appinst = _registry->impl->jobs->existing(_appid, _type.value(), instanceid, {});
964+
965+ return std::make_shared<BaseInstance>(appinst);
966+}
967+
968+std::string genInstanceId()
969+{
970+ return std::to_string(g_get_real_time());
971+}
972+
973+std::vector<Application::URL> appURL(const std::vector<Helper::URL>& in)
974+{
975+ std::vector<Application::URL> out;
976+ std::transform(in.begin(), in.end(), out.begin(),
977+ [](Helper::URL url) { return Application::URL::from_raw(url.value()); });
978+ return out;
979+}
980+
981+std::shared_ptr<Helper::Instance> Base::launch(std::vector<Helper::URL> urls)
982+{
983+ std::function<std::list<std::pair<std::string, std::string>>()> envfunc = [this]() {
984+ return std::list<std::pair<std::string, std::string>>{};
985+ };
986+
987+ return std::make_shared<BaseInstance>(_registry->impl->jobs->launch(
988+ _appid, _type.value(), genInstanceId(), appURL(urls), jobs::manager::launchMode::STANDARD, envfunc));
989+}
990+
991+class MirFDProxy
992+{
993+public:
994+ int mirfd;
995+ std::shared_ptr<proxySocketDemangler> skel;
996+ guint handle;
997+ std::string path;
998+ std::string name;
999+
1000+ MirFDProxy(MirPromptSession* session, const AppID& appid, const std::shared_ptr<Registry>& reg)
1001+ : name(g_dbus_connection_get_unique_name(reg->impl->_dbus.get()))
1002+ {
1003+ /* Get the Mir FD */
1004+ std::promise<int> promise;
1005+ mir_prompt_session_new_fds_for_prompt_providers(
1006+ session, 1,
1007+ [](MirPromptSession* session, size_t count, int const* fdin, void* user_data) {
1008+ auto promise = static_cast<std::promise<int>*>(user_data);
1009+
1010+ if (count != 1)
1011 {
1012- found = true;
1013- break;
1014+ g_warning("Mir trusted session returned %d FDs instead of one", (int)count);
1015+ promise->set_value(0);
1016+ return;
1017 }
1018- }
1019-
1020- g_strfreev(instances);
1021-
1022- return found;
1023- });
1024- }
1025-
1026- void stop() override
1027- {
1028- _registry->impl->thread.executeOnThread<bool>([this]() {
1029- return ubuntu_app_launch_stop_multiple_helper(_type.value().c_str(), ((std::string)_appid).c_str(),
1030- _instanceid.c_str()) == TRUE;
1031- });
1032+
1033+ promise->set_value(fdin[0]);
1034+ },
1035+ &promise);
1036+
1037+ mirfd = promise.get_future().get();
1038+
1039+ if (mirfd == 0)
1040+ {
1041+ throw std::runtime_error{"Unable to Mir FD from Prompt Session"};
1042+ }
1043+
1044+ /* Setup the DBus interface */
1045+ std::tie(skel, handle, path) =
1046+ reg->impl->thread.executeOnThread<std::tuple<std::shared_ptr<proxySocketDemangler>, guint, std::string>>(
1047+ [this, appid, reg]() {
1048+ auto skel = std::shared_ptr<proxySocketDemangler>(
1049+ proxy_socket_demangler_skeleton_new(),
1050+ [](proxySocketDemangler* skel) { g_clear_object(&skel); });
1051+ auto handle = g_signal_connect(G_OBJECT(skel.get()), "handle-get-mir-socket",
1052+ G_CALLBACK(staticProxyCb), this);
1053+
1054+ /* Find a path to export on */
1055+ auto dbusAppid = dbusSafe(std::string{appid});
1056+ std::string path;
1057+
1058+ while (path.empty())
1059+ {
1060+ GError* error = nullptr;
1061+ std::string tryname =
1062+ "/com/canonical/UbuntuAppLaunch/" + dbusAppid + "/" + std::to_string(rand());
1063+
1064+ g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(skel.get()), reg->impl->_dbus.get(),
1065+ tryname.c_str(), &error);
1066+
1067+ if (error == nullptr)
1068+ {
1069+ path = tryname;
1070+ }
1071+ else
1072+ {
1073+ if (!g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_OBJECT_PATH_IN_USE))
1074+ {
1075+ std::string message =
1076+ "Unable to export Mir trusted proxy: " + std::string{error->message};
1077+ g_clear_error(&error);
1078+ throw std::runtime_error{message};
1079+ }
1080+ g_clear_error(&error);
1081+ }
1082+ }
1083+
1084+ return std::make_tuple(skel, handle, path);
1085+ });
1086+ }
1087+
1088+ ~MirFDProxy()
1089+ {
1090+ if (mirfd != 0)
1091+ {
1092+ close(mirfd);
1093+ }
1094+
1095+ if (handle != 0)
1096+ {
1097+ g_signal_handler_disconnect(skel.get(), handle);
1098+ }
1099+
1100+ g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(skel.get()));
1101+ }
1102+
1103+ static std::string dbusSafe(const std::string& in)
1104+ {
1105+ std::string out = in;
1106+ std::transform(out.begin(), out.end(), out.begin(), [](char in) { return std::isalpha(in) ? in : '_'; });
1107+ return out;
1108+ }
1109+
1110+ bool proxyCb(GDBusMethodInvocation* invocation)
1111+ {
1112+ if (mirfd == 0)
1113+ {
1114+ g_warning("Mir FD proxy called with no FDs!");
1115+ return false;
1116+ }
1117+
1118+ /* Index into fds */
1119+ auto handle = g_variant_new_handle(0);
1120+ auto tuple = g_variant_new_tuple(&handle, 1);
1121+
1122+ GError* error = nullptr;
1123+ GUnixFDList* list = g_unix_fd_list_new();
1124+ g_unix_fd_list_append(list, mirfd, &error);
1125+
1126+ if (error == nullptr)
1127+ {
1128+ g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, tuple, list);
1129+ }
1130+ else
1131+ {
1132+ g_variant_ref_sink(tuple);
1133+ g_variant_unref(tuple);
1134+ }
1135+
1136+ g_object_unref(list);
1137+
1138+ if (error != nullptr)
1139+ {
1140+ g_warning("Unable to pass FD %d: %s", mirfd, error->message);
1141+ g_error_free(error);
1142+ return false;
1143+ }
1144+
1145+ mirfd = 0;
1146+ return true;
1147+ }
1148+
1149+ static gboolean staticProxyCb(GObject* obj, GDBusMethodInvocation* invocation, gpointer user_data)
1150+ {
1151+ return static_cast<MirFDProxy*>(user_data)->proxyCb(invocation) ? TRUE : FALSE;
1152+ }
1153+
1154+ std::string getPath()
1155+ {
1156+ return path;
1157+ }
1158+
1159+ std::string getName()
1160+ {
1161+ return name;
1162 }
1163 };
1164
1165-std::vector<std::shared_ptr<Click::Instance>> Click::instances()
1166-{
1167- return _registry->impl->thread.executeOnThread<std::vector<std::shared_ptr<Click::Instance>>>(
1168- [this]() -> std::vector<std::shared_ptr<Click::Instance>> {
1169- std::vector<std::shared_ptr<Click::Instance>> vect;
1170- auto instances =
1171- ubuntu_app_launch_list_helper_instances(_type.value().c_str(), ((std::string)_appid).c_str());
1172- for (int i = 0; instances[i] != nullptr; i++)
1173- {
1174- auto inst = std::make_shared<ClickInstance>(_appid, _type, instances[i], _registry);
1175- vect.push_back(inst);
1176- }
1177-
1178- g_strfreev(instances);
1179-
1180- return vect;
1181- });
1182-}
1183-
1184-std::shared_ptr<gchar*> urlsToStrv(std::vector<Helper::URL> urls)
1185-{
1186- if (urls.size() == 0)
1187- {
1188+std::shared_ptr<Helper::Instance> Base::launch(MirPromptSession* session, std::vector<Helper::URL> urls)
1189+{
1190+ std::shared_ptr<MirFDProxy> proxy;
1191+ try
1192+ {
1193+ proxy = std::make_shared<MirFDProxy>(session, _appid, _registry);
1194+ }
1195+ catch (std::runtime_error& e)
1196+ {
1197+ g_warning("Error launching helper: %s", e.what());
1198 return {};
1199 }
1200
1201- auto array = g_array_new(TRUE, FALSE, sizeof(gchar*));
1202-
1203- for (auto url : urls)
1204- {
1205- auto str = g_strdup(url.value().c_str());
1206- g_array_append_val(array, str);
1207- }
1208-
1209- return std::shared_ptr<gchar*>((gchar**)g_array_free(array, FALSE), g_strfreev);
1210-}
1211-
1212-std::shared_ptr<Click::Instance> Click::launch(std::vector<Helper::URL> urls)
1213-{
1214- auto urlstrv = urlsToStrv(urls);
1215-
1216- return _registry->impl->thread.executeOnThread<std::shared_ptr<Click::Instance>>([this, urlstrv]() {
1217- auto instanceid = ubuntu_app_launch_start_multiple_helper(_type.value().c_str(), ((std::string)_appid).c_str(),
1218- urlstrv.get());
1219- auto ret = std::make_shared<ClickInstance>(_appid, _type, instanceid, _registry);
1220- g_free(instanceid);
1221- return ret;
1222- });
1223-}
1224-
1225-std::shared_ptr<Click::Instance> Click::launch(MirPromptSession* session, std::vector<Helper::URL> urls)
1226-{
1227- auto urlstrv = urlsToStrv(urls);
1228-
1229- return _registry->impl->thread.executeOnThread<std::shared_ptr<Click::Instance>>([this, session, urlstrv]() {
1230- auto instanceid = ubuntu_app_launch_start_session_helper(_type.value().c_str(), session,
1231- ((std::string)_appid).c_str(), urlstrv.get());
1232-
1233- return std::make_shared<ClickInstance>(_appid, _type, instanceid, _registry);
1234- });
1235-}
1236-
1237-std::list<std::shared_ptr<Helper>> Click::running(Helper::Type type, std::shared_ptr<Registry> registry)
1238-{
1239- return registry->impl->thread.executeOnThread<std::list<std::shared_ptr<Helper>>>([type, registry]() {
1240- std::list<std::shared_ptr<Helper>> helpers;
1241-
1242- auto appidv = ubuntu_app_launch_list_helpers(type.value().c_str());
1243- for (int i = 0; appidv[i] != nullptr; i++)
1244- {
1245- auto helper = std::make_shared<Click>(type, AppID::parse(appidv[i]), registry);
1246- helpers.push_back(helper);
1247- }
1248-
1249- g_strfreev(appidv);
1250-
1251- return helpers;
1252- });
1253+ std::function<std::list<std::pair<std::string, std::string>>()> envfunc = [proxy]() {
1254+ std::list<std::pair<std::string, std::string>> envs;
1255+
1256+ envs.emplace_back(std::make_pair("UBUNTU_APP_LAUNCH_DEMANGLE_PATH", proxy->getPath()));
1257+ envs.emplace_back(std::make_pair("UBUNTU_APP_LAUNCH_DEMANGLE_NAME", proxy->getName()));
1258+
1259+ return envs;
1260+ };
1261+
1262+ /* This will maintain a reference to the proxy for two
1263+ seconds. And then it'll be dropped. */
1264+ _registry->impl->thread.timeout(std::chrono::seconds{2}, [proxy]() { g_debug("Mir Proxy Timeout"); });
1265+
1266+ return std::make_shared<BaseInstance>(_registry->impl->jobs->launch(
1267+ _appid, _type.value(), genInstanceId(), appURL(urls), jobs::manager::launchMode::STANDARD, envfunc));
1268 }
1269
1270 } // namespace helper_impl
1271+
1272+/***************************/
1273+/* Helper Public Functions */
1274+/***************************/
1275+
1276+std::shared_ptr<Helper> Helper::create(Type type, AppID appid, std::shared_ptr<Registry> registry)
1277+{
1278+ /* Only one type today */
1279+ return std::make_shared<helper_impls::Base>(type, appid, registry);
1280+}
1281+
1282+void Helper::setExec(std::vector<std::string> exec)
1283+{
1284+}
1285+
1286 } // namespace app_launch
1287 } // namespace ubuntu
1288
1289=== removed file 'libubuntu-app-launch/helper.cpp'
1290--- libubuntu-app-launch/helper.cpp 2016-06-09 14:55:34 +0000
1291+++ libubuntu-app-launch/helper.cpp 1970-01-01 00:00:00 +0000
1292@@ -1,36 +0,0 @@
1293-/*
1294- * Copyright © 2016 Canonical Ltd.
1295- *
1296- * This program is free software: you can redistribute it and/or modify it
1297- * under the terms of the GNU General Public License version 3, as published
1298- * by the Free Software Foundation.
1299- *
1300- * This program is distributed in the hope that it will be useful, but
1301- * WITHOUT ANY WARRANTY; without even the implied warranties of
1302- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1303- * PURPOSE. See the GNU General Public License for more details.
1304- *
1305- * You should have received a copy of the GNU General Public License along
1306- * with this program. If not, see <http://www.gnu.org/licenses/>.
1307- *
1308- * Authors:
1309- * Ted Gould <ted.gould@canonical.com>
1310- */
1311-
1312-#include "helper.h"
1313-
1314-#include "helper-impl-click.h"
1315-
1316-namespace ubuntu
1317-{
1318-namespace app_launch
1319-{
1320-
1321-std::shared_ptr<Helper> Helper::create(Type type, AppID appid, std::shared_ptr<Registry> registry)
1322-{
1323- /* Only one type today */
1324- return std::make_shared<helper_impls::Click>(type, appid, registry);
1325-}
1326-
1327-} // namespace AppLaunch
1328-} // namespace Ubuntu
1329
1330=== modified file 'libubuntu-app-launch/helper.h'
1331--- libubuntu-app-launch/helper.h 2017-01-26 22:46:49 +0000
1332+++ libubuntu-app-launch/helper.h 2017-02-22 21:41:30 +0000
1333@@ -126,6 +126,12 @@
1334 \param urls List of URLs to passed to the untrusted helper
1335 */
1336 virtual std::shared_ptr<Instance> launch(MirPromptSession* session, std::vector<URL> urls = {}) = 0;
1337+ /** Set the exec from a helper utility. This function should only
1338+ be used inside a helper exec util.
1339+
1340+ \param exec The exec line to use for the helper with the AppID given
1341+ */
1342+ static void setExec(std::vector<std::string> exec);
1343 };
1344
1345 } // namespace app_launch
1346
1347=== modified file 'libubuntu-app-launch/jobs-base.cpp'
1348--- libubuntu-app-launch/jobs-base.cpp 2017-01-26 22:46:06 +0000
1349+++ libubuntu-app-launch/jobs-base.cpp 2017-02-22 21:41:30 +0000
1350@@ -23,9 +23,9 @@
1351 #include <numeric>
1352
1353 #include "application-impl-base.h"
1354+#include "helper-impl.h"
1355 #include "jobs-base.h"
1356 #include "jobs-systemd.h"
1357-#include "jobs-upstart.h"
1358 #include "registry-impl.h"
1359
1360 namespace ubuntu
1361@@ -61,29 +61,87 @@
1362 dohandle(handle_appResumed);
1363 }
1364
1365+/** Should determine which jobs backend to use, but we only have
1366+ one right now. */
1367 std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry)
1368 {
1369- /* Checking to see if we have a user bus, that is only started
1370- by systemd so we're in good shape if we have one. We're using
1371- the path instead of the RUNTIME variable because we want to work
1372- around the case of being relocated by the snappy environment */
1373- if (g_file_test(SystemD::userBusPath().c_str(), G_FILE_TEST_EXISTS))
1374- {
1375- g_debug("Building a systemd jobs manager");
1376- return std::make_shared<jobs::manager::SystemD>(registry);
1377- }
1378- else
1379- {
1380- g_debug("Building an Upstart jobs manager");
1381- return std::make_shared<jobs::manager::Upstart>(registry);
1382- }
1383+ g_debug("Building a systemd jobs manager");
1384+ return std::make_shared<jobs::manager::SystemD>(registry);
1385 }
1386
1387-const std::set<std::string>& Base::getAllJobs() const
1388+const std::list<std::string>& Base::getAllJobs() const
1389 {
1390 return allJobs_;
1391 }
1392
1393+core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Base::appStarted()
1394+{
1395+ std::call_once(flag_appStarted, [this]() {
1396+ jobStarted().connect([this](const std::string& job, const std::string& appid, const std::string& instanceid) {
1397+ if (std::find(allJobs_.begin(), allJobs_.end(), job) == allJobs_.end())
1398+ {
1399+ return;
1400+ }
1401+
1402+ auto reg = registry_.lock();
1403+
1404+ auto appId = AppID::find(reg, appid);
1405+ auto app = Application::create(appId, reg);
1406+ auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
1407+
1408+ sig_appStarted(app, inst);
1409+ });
1410+ });
1411+
1412+ return sig_appStarted;
1413+}
1414+
1415+core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Base::appStopped()
1416+{
1417+ std::call_once(flag_appStopped, [this]() {
1418+ jobStopped().connect([this](const std::string& job, const std::string& appid, const std::string& instanceid) {
1419+ if (std::find(allJobs_.begin(), allJobs_.end(), job) == allJobs_.end())
1420+ {
1421+ return;
1422+ }
1423+
1424+ auto reg = registry_.lock();
1425+
1426+ auto appId = AppID::find(reg, appid);
1427+ auto app = Application::create(appId, reg);
1428+ auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
1429+
1430+ sig_appStopped(app, inst);
1431+ });
1432+ });
1433+
1434+ return sig_appStopped;
1435+}
1436+
1437+core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>&
1438+ Base::appFailed()
1439+{
1440+ std::call_once(flag_appFailed, [this]() {
1441+ jobFailed().connect([this](const std::string& job, const std::string& appid, const std::string& instanceid,
1442+ Registry::FailureType reason) {
1443+ if (std::find(allJobs_.begin(), allJobs_.end(), job) == allJobs_.end())
1444+ {
1445+ return;
1446+ }
1447+
1448+ auto reg = registry_.lock();
1449+
1450+ auto appId = AppID::find(reg, appid);
1451+ auto app = Application::create(appId, reg);
1452+ auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
1453+
1454+ sig_appFailed(app, inst, reason);
1455+ });
1456+ });
1457+
1458+ return sig_appFailed;
1459+}
1460+
1461 /** Structure to track the data needed for upstart events. This cleans
1462 up the lifecycle as we're passing this as a pointer through the
1463 GLib calls. */
1464@@ -229,6 +287,127 @@
1465 return sig_appResumed;
1466 }
1467
1468+core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& Base::helperStarted(
1469+ Helper::Type type)
1470+{
1471+ try
1472+ {
1473+ return *sig_helpersStarted.at(type.value());
1474+ }
1475+ catch (std::out_of_range& e)
1476+ {
1477+ jobStarted().connect(
1478+ [this, type](const std::string& job, const std::string& appid, const std::string& instanceid) {
1479+ if (job != type.value())
1480+ {
1481+ return;
1482+ }
1483+
1484+ try
1485+ {
1486+ auto reg = registry_.lock();
1487+
1488+ auto appId = ubuntu::app_launch::AppID::parse(appid);
1489+ auto helper = Helper::create(type, appId, reg);
1490+ auto inst = std::dynamic_pointer_cast<helper_impls::Base>(helper)->existingInstance(instanceid);
1491+
1492+ (*sig_helpersStarted.at(type.value()))(helper, inst);
1493+ }
1494+ catch (...)
1495+ {
1496+ g_warning("Unable to emit signal for helper type: %s", type.value().c_str());
1497+ }
1498+ });
1499+
1500+ sig_helpersStarted.emplace(
1501+ type.value(),
1502+ std::make_shared<core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>>());
1503+ }
1504+
1505+ return *sig_helpersStarted.at(type.value());
1506+}
1507+
1508+core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& Base::helperStopped(
1509+ Helper::Type type)
1510+{
1511+ try
1512+ {
1513+ return *sig_helpersStopped.at(type.value());
1514+ }
1515+ catch (std::out_of_range& e)
1516+ {
1517+ jobStopped().connect(
1518+ [this, type](const std::string& job, const std::string& appid, const std::string& instanceid) {
1519+ if (job != type.value())
1520+ {
1521+ return;
1522+ }
1523+
1524+ try
1525+ {
1526+ auto reg = registry_.lock();
1527+
1528+ auto appId = ubuntu::app_launch::AppID::parse(appid);
1529+ auto helper = Helper::create(type, appId, reg);
1530+ auto inst = std::dynamic_pointer_cast<helper_impls::Base>(helper)->existingInstance(instanceid);
1531+
1532+ (*sig_helpersStopped.at(type.value()))(helper, inst);
1533+ }
1534+ catch (...)
1535+ {
1536+ g_warning("Unable to emit signal for helper type: %s", type.value().c_str());
1537+ }
1538+ });
1539+
1540+ sig_helpersStopped.emplace(
1541+ type.value(),
1542+ std::make_shared<core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>>());
1543+ }
1544+
1545+ return *sig_helpersStopped.at(type.value());
1546+}
1547+
1548+core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&, Registry::FailureType>&
1549+ Base::helperFailed(Helper::Type type)
1550+{
1551+ try
1552+ {
1553+ return *sig_helpersFailed.at(type.value());
1554+ }
1555+ catch (std::out_of_range& e)
1556+ {
1557+ jobFailed().connect([this, type](const std::string& job, const std::string& appid,
1558+ const std::string& instanceid, Registry::FailureType reason) {
1559+ if (job != type.value())
1560+ {
1561+ return;
1562+ }
1563+
1564+ try
1565+ {
1566+ auto reg = registry_.lock();
1567+
1568+ auto appId = ubuntu::app_launch::AppID::parse(appid);
1569+ auto helper = Helper::create(type, appId, reg);
1570+ auto inst = std::dynamic_pointer_cast<helper_impls::Base>(helper)->existingInstance(instanceid);
1571+
1572+ (*sig_helpersFailed.at(type.value()))(helper, inst, reason);
1573+ }
1574+ catch (...)
1575+ {
1576+ g_warning("Unable to emit signal for helper type: %s", type.value().c_str());
1577+ }
1578+ });
1579+
1580+ sig_helpersFailed.emplace(
1581+ type.value(),
1582+ std::make_shared<core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&,
1583+ Registry::FailureType>>());
1584+ }
1585+
1586+ return *sig_helpersFailed.at(type.value());
1587+}
1588+
1589 /** Take the GVariant of parameters and turn them into an application and
1590 and instance. Easier to read in the smaller function */
1591 std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Base::managerParams(
1592@@ -426,6 +605,66 @@
1593 manager_.reset();
1594 }
1595
1596+/** Get application objects for all of the applications based
1597+ on the appids associated with the application jobs */
1598+std::list<std::shared_ptr<Application>> Base::runningApps()
1599+{
1600+ auto registry = registry_.lock();
1601+
1602+ if (!registry)
1603+ {
1604+ g_warning("Unable to list apps without a registry");
1605+ return {};
1606+ }
1607+
1608+ auto appids = runningAppIds(allJobs_);
1609+
1610+ std::list<std::shared_ptr<Application>> apps;
1611+ for (const auto& appid : appids)
1612+ {
1613+ auto id = AppID::find(registry, appid);
1614+ if (id.empty())
1615+ {
1616+ g_debug("Unable to handle AppID: %s", appid.c_str());
1617+ continue;
1618+ }
1619+
1620+ apps.emplace_back(Application::create(id, registry));
1621+ }
1622+
1623+ return apps;
1624+}
1625+
1626+/** Get application objects for all of the applications based
1627+ on the appids associated with the application jobs */
1628+std::list<std::shared_ptr<Helper>> Base::runningHelpers(const Helper::Type& type)
1629+{
1630+ auto registry = registry_.lock();
1631+
1632+ if (!registry)
1633+ {
1634+ g_warning("Unable to list helpers without a registry");
1635+ return {};
1636+ }
1637+
1638+ auto appids = runningAppIds({type.value()});
1639+
1640+ std::list<std::shared_ptr<Helper>> helpers;
1641+ for (const auto& appid : appids)
1642+ {
1643+ auto id = AppID::parse(appid);
1644+ if (id.empty())
1645+ {
1646+ g_debug("Unable to handle AppID: %s", appid.c_str());
1647+ continue;
1648+ }
1649+
1650+ helpers.emplace_back(Helper::create(type, id, registry));
1651+ }
1652+
1653+ return helpers;
1654+}
1655+
1656 } // namespace manager
1657
1658 namespace instance
1659
1660=== modified file 'libubuntu-app-launch/jobs-base.h'
1661--- libubuntu-app-launch/jobs-base.h 2017-01-26 22:46:06 +0000
1662+++ libubuntu-app-launch/jobs-base.h 2017-02-22 21:41:30 +0000
1663@@ -24,6 +24,7 @@
1664
1665 #include <core/signal.h>
1666 #include <gio/gio.h>
1667+#include <map>
1668 #include <set>
1669
1670 namespace ubuntu
1671@@ -50,6 +51,11 @@
1672 void pause() override;
1673 void resume() override;
1674
1675+ const std::string& getInstanceId()
1676+ {
1677+ return instance_;
1678+ }
1679+
1680 /* OOM Functions */
1681 void setOomAdjustment(const oom::Score score) override;
1682 const oom::Score getOomAdjustment() override;
1683@@ -111,23 +117,26 @@
1684 const std::string& instance,
1685 const std::vector<Application::URL>& urls) = 0;
1686
1687- virtual std::list<std::shared_ptr<Application>> runningApps() = 0;
1688+ virtual std::list<std::shared_ptr<Application>> runningApps();
1689+ virtual std::list<std::shared_ptr<Helper>> runningHelpers(const Helper::Type& type);
1690+
1691+ virtual std::list<std::string> runningAppIds(const std::list<std::string>& jobs) = 0;
1692
1693 virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) = 0;
1694
1695- const std::set<std::string>& getAllJobs() const;
1696+ const std::list<std::string>& getAllJobs() const;
1697
1698 static std::shared_ptr<Base> determineFactory(std::shared_ptr<Registry> registry);
1699
1700 /* Signals to apps */
1701 virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
1702- appStarted() = 0;
1703+ appStarted();
1704 virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
1705- appStopped() = 0;
1706+ appStopped();
1707 virtual core::Signal<const std::shared_ptr<Application>&,
1708 const std::shared_ptr<Application::Instance>&,
1709 Registry::FailureType>&
1710- appFailed() = 0;
1711+ appFailed();
1712 virtual core::Signal<const std::shared_ptr<Application>&,
1713 const std::shared_ptr<Application::Instance>&,
1714 const std::vector<pid_t>&>&
1715@@ -136,6 +145,19 @@
1716 const std::shared_ptr<Application::Instance>&,
1717 const std::vector<pid_t>&>&
1718 appResumed();
1719+ /* Signals to helpers */
1720+ virtual core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& helperStarted(
1721+ Helper::Type type);
1722+ virtual core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& helperStopped(
1723+ Helper::Type type);
1724+ virtual core::
1725+ Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&, Registry::FailureType>&
1726+ helperFailed(Helper::Type type);
1727+ /* Job signals from implementations */
1728+ virtual core::Signal<const std::string&, const std::string&, const std::string&>& jobStarted() = 0;
1729+ virtual core::Signal<const std::string&, const std::string&, const std::string&>& jobStopped() = 0;
1730+ virtual core::Signal<const std::string&, const std::string&, const std::string&, Registry::FailureType>&
1731+ jobFailed() = 0;
1732
1733 /* App manager */
1734 virtual void setManager(std::shared_ptr<Registry::Manager> manager);
1735@@ -146,7 +168,7 @@
1736 std::weak_ptr<Registry> registry_;
1737
1738 /** A set of all the job names */
1739- std::set<std::string> allJobs_;
1740+ std::list<std::string> allJobs_;
1741
1742 /** The DBus connection we're connecting to */
1743 std::shared_ptr<GDBusConnection> dbus_;
1744@@ -154,6 +176,7 @@
1745 /** Application manager instance */
1746 std::shared_ptr<Registry::Manager> manager_;
1747
1748+private:
1749 /** Signal object for applications started */
1750 core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&> sig_appStarted;
1751 /** Signal object for applications stopped */
1752@@ -174,7 +197,18 @@
1753 const std::vector<pid_t>&>
1754 sig_appResumed;
1755
1756-private:
1757+ std::map<std::string,
1758+ std::shared_ptr<core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>>>
1759+ sig_helpersStarted;
1760+ std::map<std::string,
1761+ std::shared_ptr<core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>>>
1762+ sig_helpersStopped;
1763+ std::map<std::string,
1764+ std::shared_ptr<core::Signal<const std::shared_ptr<Helper>&,
1765+ const std::shared_ptr<Helper::Instance>&,
1766+ Registry::FailureType>>>
1767+ sig_helpersFailed;
1768+
1769 guint handle_managerSignalFocus{0}; /**< GDBus signal watcher handle for app focused signal */
1770 guint handle_managerSignalResume{0}; /**< GDBus signal watcher handle for app resumed signal */
1771 guint handle_managerSignalStarting{0}; /**< GDBus signal watcher handle for app starting signal */
1772@@ -183,6 +217,12 @@
1773
1774 std::once_flag flag_managerSignals; /**< Variable to track to see if signal handlers are installed for the manager
1775 signals of focused, resumed and starting */
1776+ std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application
1777+ started */
1778+ std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application
1779+ stopped */
1780+ std::once_flag
1781+ flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */
1782 std::once_flag
1783 flag_appPaused; /**< Variable to track to see if signal handlers are installed for application paused */
1784 std::once_flag flag_appResumed; /**< Variable to track to see if signal handlers are installed for application
1785
1786=== modified file 'libubuntu-app-launch/jobs-systemd.cpp'
1787--- libubuntu-app-launch/jobs-systemd.cpp 2017-02-04 04:06:20 +0000
1788+++ libubuntu-app-launch/jobs-systemd.cpp 2017-02-22 21:41:30 +0000
1789@@ -239,7 +239,7 @@
1790 try
1791 {
1792 auto info = pthis->unitNew(unitname, unitpath, pthis->userbus_);
1793- pthis->emitSignal(pthis->sig_appStarted, info);
1794+ pthis->sig_jobStarted(info.job, info.appid, info.inst);
1795 }
1796 catch (std::runtime_error& e)
1797 {
1798@@ -869,7 +869,7 @@
1799 return instances;
1800 }
1801
1802-std::list<std::shared_ptr<Application>> SystemD::runningApps()
1803+std::list<std::string> SystemD::runningAppIds(const std::list<std::string>& allJobs)
1804 {
1805 auto registry = registry_.lock();
1806
1807@@ -879,14 +879,13 @@
1808 return {};
1809 }
1810
1811- auto allJobs = getAllJobs();
1812 std::set<std::string> appids;
1813
1814 for (const auto& unit : unitPaths)
1815 {
1816 const SystemD::UnitInfo& unitinfo = unit.first;
1817
1818- if (allJobs.find(unitinfo.job) == allJobs.end())
1819+ if (std::find(allJobs.begin(), allJobs.end(), unitinfo.job) == allJobs.end())
1820 {
1821 continue;
1822 }
1823@@ -894,20 +893,7 @@
1824 appids.insert(unitinfo.appid);
1825 }
1826
1827- std::list<std::shared_ptr<Application>> apps;
1828- for (const auto& appid : appids)
1829- {
1830- auto id = AppID::find(registry, appid);
1831- if (id.empty())
1832- {
1833- g_debug("Unable to handle AppID: %s", appid.c_str());
1834- continue;
1835- }
1836-
1837- apps.emplace_back(Application::create(id, registry));
1838- }
1839-
1840- return apps;
1841+ return {appids.begin(), appids.end()};
1842 }
1843
1844 std::string SystemD::userBusPath()
1845@@ -1038,26 +1024,8 @@
1846 if (it != unitPaths.end())
1847 {
1848 unitPaths.erase(it);
1849- emitSignal(sig_appStopped, info);
1850- }
1851-}
1852-
1853-void SystemD::emitSignal(
1854- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& sig,
1855- UnitInfo& info)
1856-{
1857- auto reg = registry_.lock();
1858- if (!reg)
1859- {
1860- g_warning("Unable to emit systemd signal, invalid registry");
1861- return;
1862- }
1863-
1864- auto appid = AppID::find(reg, info.appid);
1865- auto app = Application::create(appid, reg);
1866- auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(info.inst);
1867-
1868- sig(app, inst);
1869+ sig_jobStopped(info.job, info.appid, info.inst);
1870+ }
1871 }
1872
1873 pid_t SystemD::unitPrimaryPid(const AppID& appId, const std::string& job, const std::string& instance)
1874@@ -1252,18 +1220,18 @@
1875 });
1876 }
1877
1878-core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& SystemD::appStarted()
1879+core::Signal<const std::string&, const std::string&, const std::string&>& SystemD::jobStarted()
1880 {
1881 /* For systemd we're automatically listening to the UnitNew signal
1882 and emitting on the object */
1883- return sig_appStarted;
1884+ return sig_jobStarted;
1885 }
1886
1887-core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& SystemD::appStopped()
1888+core::Signal<const std::string&, const std::string&, const std::string&>& SystemD::jobStopped()
1889 {
1890 /* For systemd we're automatically listening to the UnitRemoved signal
1891 and emitting on the object */
1892- return sig_appStopped;
1893+ return sig_jobStopped;
1894 }
1895
1896 struct FailedData
1897@@ -1271,8 +1239,7 @@
1898 std::weak_ptr<Registry> registry;
1899 };
1900
1901-core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>&
1902- SystemD::appFailed()
1903+core::Signal<const std::string&, const std::string&, const std::string&, Registry::FailureType>& SystemD::jobFailed()
1904 {
1905 std::call_once(flag_appFailed, [this]() {
1906 auto reg = registry_.lock();
1907@@ -1352,11 +1319,7 @@
1908 reason = Registry::FailureType::START_FAILURE;
1909 }
1910
1911- auto appid = AppID::find(reg, unitinfo.appid);
1912- auto app = Application::create(appid, reg);
1913- auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(unitinfo.inst);
1914-
1915- manager->sig_appFailed(app, inst, reason);
1916+ manager->sig_jobFailed(unitinfo.job, unitinfo.appid, unitinfo.inst, reason);
1917 }, /* callback */
1918 data, /* user data */
1919 [](gpointer user_data) {
1920@@ -1368,7 +1331,7 @@
1921 });
1922 });
1923
1924- return sig_appFailed;
1925+ return sig_jobFailed;
1926 }
1927
1928 /** Requests that systemd reset a unit that has been marked as
1929
1930=== modified file 'libubuntu-app-launch/jobs-systemd.h'
1931--- libubuntu-app-launch/jobs-systemd.h 2017-02-02 22:51:42 +0000
1932+++ libubuntu-app-launch/jobs-systemd.h 2017-02-22 21:41:30 +0000
1933@@ -53,18 +53,14 @@
1934 const std::string& instance,
1935 const std::vector<Application::URL>& urls) override;
1936
1937- virtual std::list<std::shared_ptr<Application>> runningApps() override;
1938+ virtual std::list<std::string> runningAppIds(const std::list<std::string>& jobs) override;
1939
1940 virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) override;
1941
1942- virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
1943- appStarted() override;
1944- virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
1945- appStopped() override;
1946- virtual core::Signal<const std::shared_ptr<Application>&,
1947- const std::shared_ptr<Application::Instance>&,
1948- Registry::FailureType>&
1949- appFailed() override;
1950+ virtual core::Signal<const std::string&, const std::string&, const std::string&>& jobStarted() override;
1951+ virtual core::Signal<const std::string&, const std::string&, const std::string&>& jobStopped() override;
1952+ virtual core::Signal<const std::string&, const std::string&, const std::string&, Registry::FailureType>& jobFailed()
1953+ override;
1954
1955 static std::string userBusPath();
1956
1957@@ -76,6 +72,10 @@
1958 std::string cgroup_root_;
1959 std::shared_ptr<GDBusConnection> userbus_;
1960
1961+ core::Signal<const std::string&, const std::string&, const std::string&> sig_jobStarted;
1962+ core::Signal<const std::string&, const std::string&, const std::string&> sig_jobStopped;
1963+ core::Signal<const std::string&, const std::string&, const std::string&, Registry::FailureType> sig_jobFailed;
1964+
1965 guint handle_unitNew{0}; /**< GDBus signal watcher handle for the unit new signal */
1966 guint handle_unitRemoved{0}; /**< GDBus signal watcher handle for the unit removed signal */
1967 guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */
1968@@ -116,9 +116,6 @@
1969
1970 UnitInfo unitNew(const std::string& name, const std::string& path, const std::shared_ptr<GDBusConnection>& bus);
1971 void unitRemoved(const std::string& name, const std::string& path);
1972- void emitSignal(
1973- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& sig,
1974- UnitInfo& info);
1975
1976 static std::string findEnv(const std::string& value, std::list<std::pair<std::string, std::string>>& env);
1977 static void removeEnv(const std::string& value, std::list<std::pair<std::string, std::string>>& env);
1978
1979=== removed file 'libubuntu-app-launch/jobs-upstart.cpp'
1980--- libubuntu-app-launch/jobs-upstart.cpp 2017-01-11 23:48:12 +0000
1981+++ libubuntu-app-launch/jobs-upstart.cpp 1970-01-01 00:00:00 +0000
1982@@ -1,1211 +0,0 @@
1983-/*
1984- * Copyright © 2016 Canonical Ltd.
1985- *
1986- * This program is free software: you can redistribute it and/or modify it
1987- * under the terms of the GNU General Public License version 3, as published
1988- * by the Free Software Foundation.
1989- *
1990- * This program is distributed in the hope that it will be useful, but
1991- * WITHOUT ANY WARRANTY; without even the implied warranties of
1992- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1993- * PURPOSE. See the GNU General Public License for more details.
1994- *
1995- * You should have received a copy of the GNU General Public License along
1996- * with this program. If not, see <http://www.gnu.org/licenses/>.
1997- *
1998- * Authors:
1999- * Ted Gould <ted.gould@canonical.com>
2000- */
2001-
2002-#include <algorithm>
2003-#include <cerrno>
2004-#include <cstring>
2005-#include <map>
2006-#include <numeric>
2007-#include <regex>
2008-
2009-#include <cgmanager/cgmanager.h>
2010-#include <upstart.h>
2011-
2012-#include "application-impl-base.h"
2013-#include "helpers.h"
2014-#include "registry-impl.h"
2015-#include "second-exec-core.h"
2016-
2017-extern "C" {
2018-#include "ubuntu-app-launch-trace.h"
2019-}
2020-
2021-#include "jobs-upstart.h"
2022-
2023-namespace ubuntu
2024-{
2025-namespace app_launch
2026-{
2027-namespace jobs
2028-{
2029-namespace instance
2030-{
2031-
2032-/** An object that represents an instance of a job on Upstart. This
2033- then implements everything needed by the instance interface. Most
2034- applications tie into this today and use it as the backend for
2035- their instances. */
2036-class Upstart : public Base
2037-{
2038-public:
2039- explicit Upstart(const AppID& appId,
2040- const std::string& job,
2041- const std::string& instance,
2042- const std::vector<Application::URL>& urls,
2043- const std::shared_ptr<Registry>& registry);
2044-
2045- /* Query lifecycle */
2046- pid_t primaryPid() override;
2047- std::string logPath() override;
2048- std::vector<pid_t> pids() override;
2049-
2050- /* Manage lifecycle */
2051- void stop() override;
2052- void pause() override;
2053- void resume() override;
2054-
2055- /* C Callback */
2056- static void application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data);
2057-
2058-private:
2059- std::string upstartJobPath();
2060- std::string upstartName();
2061-
2062- static std::vector<pid_t> pids(const std::shared_ptr<Registry>& reg,
2063- const AppID& appid,
2064- const std::string& jobpath);
2065- static std::vector<pid_t> forAllPids(const std::shared_ptr<Registry>& reg,
2066- const AppID& appid,
2067- const std::string& jobpath,
2068- std::function<void(pid_t)> eachPid);
2069-};
2070-
2071-/** Uses Upstart to get the primary PID of the instance using Upstart's
2072- DBus interface */
2073-pid_t Upstart::primaryPid()
2074-{
2075- auto jobpath = upstartJobPath();
2076- if (jobpath.empty())
2077- {
2078- g_debug("Unable to get a valid job path");
2079- return 0;
2080- }
2081-
2082- return registry_->impl->thread.executeOnThread<pid_t>([this, &jobpath]() -> pid_t {
2083- GError* error = nullptr;
2084-
2085- std::string instancename = std::string(appId_);
2086- if (job_ != "application-click")
2087- {
2088- instancename += "-" + instance_;
2089- }
2090-
2091- g_debug("Getting instance by name: %s", instance_.c_str());
2092- auto vinstance_path =
2093- g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* connection */
2094- DBUS_SERVICE_UPSTART, /* service */
2095- jobpath.c_str(), /* object path */
2096- DBUS_INTERFACE_UPSTART_JOB, /* iface */
2097- "GetInstanceByName", /* method */
2098- g_variant_new("(s)", instancename.c_str()), /* params */
2099- G_VARIANT_TYPE("(o)"), /* return type */
2100- G_DBUS_CALL_FLAGS_NONE, /* flags */
2101- -1, /* timeout: default */
2102- registry_->impl->thread.getCancellable().get(), /* cancellable */
2103- &error);
2104-
2105- if (error != nullptr)
2106- {
2107- g_warning("Unable to get instance '%s' of job '%s': %s", instance_.c_str(), job_.c_str(), error->message);
2108- g_error_free(error);
2109- return 0;
2110- }
2111-
2112- /* Jump rope to make this into a C++ type */
2113- std::string instance_path;
2114- gchar* cinstance_path = nullptr;
2115- g_variant_get(vinstance_path, "(o)", &cinstance_path);
2116- g_variant_unref(vinstance_path);
2117- if (cinstance_path != nullptr)
2118- {
2119- instance_path = cinstance_path;
2120- g_free(cinstance_path);
2121- }
2122-
2123- if (instance_path.empty())
2124- {
2125- g_debug("No instance object for instance name: %s", instance_.c_str());
2126- return 0;
2127- }
2128-
2129- auto props_tuple =
2130- g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* connection */
2131- DBUS_SERVICE_UPSTART, /* service */
2132- instance_path.c_str(), /* object path */
2133- "org.freedesktop.DBus.Properties", /* interface */
2134- "GetAll", /* method */
2135- g_variant_new("(s)", DBUS_INTERFACE_UPSTART_INSTANCE), /* params */
2136- G_VARIANT_TYPE("(a{sv})"), /* return type */
2137- G_DBUS_CALL_FLAGS_NONE, /* flags */
2138- -1, /* timeout: default */
2139- registry_->impl->thread.getCancellable().get(), /* cancellable */
2140- &error);
2141-
2142- if (error != nullptr)
2143- {
2144- g_warning("Unable to name of properties '%s': %s", instance_path.c_str(), error->message);
2145- g_error_free(error);
2146- error = nullptr;
2147- return 0;
2148- }
2149-
2150- auto props_dict = g_variant_get_child_value(props_tuple, 0);
2151-
2152- pid_t retval = 0;
2153- auto processes = g_variant_lookup_value(props_dict, "processes", G_VARIANT_TYPE("a(si)"));
2154- if (processes != nullptr && g_variant_n_children(processes) > 0)
2155- {
2156-
2157- auto first_entry = g_variant_get_child_value(processes, 0);
2158- auto pidv = g_variant_get_child_value(first_entry, 1);
2159-
2160- retval = g_variant_get_int32(pidv);
2161-
2162- g_variant_unref(pidv);
2163- g_variant_unref(first_entry);
2164- }
2165- else
2166- {
2167- g_debug("Unable to get 'processes' from properties of instance at path: %s", instance_path.c_str());
2168- }
2169-
2170- g_variant_unref(props_dict);
2171-
2172- return retval;
2173- });
2174-}
2175-
2176-/** Generate the full name of the Upstart job for the job, the
2177- instance and how all those fit together.
2178-
2179- Handles the special case of application-click which isn't designed
2180- to have multi-instance apps.
2181-*/
2182-std::string Upstart::upstartName()
2183-{
2184- std::string path = job_ + "-" + std::string(appId_);
2185- if (job_ != "application-click")
2186- {
2187- path += "-";
2188- }
2189- if (!instance_.empty())
2190- {
2191- path += instance_;
2192- }
2193-
2194- return path;
2195-}
2196-
2197-/** Gets the path to the log file for this instance */
2198-std::string Upstart::logPath()
2199-{
2200- std::string logfile = upstartName() + ".log";
2201-
2202- gchar* cpath = g_build_filename(g_get_user_cache_dir(), "upstart", logfile.c_str(), nullptr);
2203- std::string path(cpath);
2204- g_free(cpath);
2205-
2206- return path;
2207-}
2208-
2209-/** Returns all the PIDs that are in the cgroup for this application */
2210-std::vector<pid_t> Upstart::pids()
2211-{
2212- auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry_->impl->jobs);
2213- auto pids = manager->pidsFromCgroup(upstartName());
2214- g_debug("Got %d PIDs for AppID '%s'", int(pids.size()), std::string(appId_).c_str());
2215- return pids;
2216-}
2217-
2218-/** Stops this instance by asking Upstart to stop it. Upstart will then
2219- send a SIGTERM and five seconds later start killing things. */
2220-void Upstart::stop()
2221-{
2222- if (!registry_->impl->thread.executeOnThread<bool>([this]() {
2223- auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry_->impl->jobs);
2224-
2225- g_debug("Stopping job %s app_id %s instance_id %s", job_.c_str(), std::string(appId_).c_str(),
2226- instance_.c_str());
2227-
2228- auto jobpath = upstartJobPath();
2229- if (jobpath.empty())
2230- {
2231- throw new std::runtime_error("Unable to get job path for Upstart job '" + job_ + "'");
2232- }
2233-
2234- GVariantBuilder builder;
2235- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
2236- g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
2237-
2238- g_variant_builder_add_value(
2239- &builder, g_variant_new_take_string(g_strdup_printf("APP_ID=%s", std::string(appId_).c_str())));
2240-
2241- if (!instance_.empty())
2242- {
2243- g_variant_builder_add_value(
2244- &builder, g_variant_new_take_string(g_strdup_printf("INSTANCE_ID=%s", instance_.c_str())));
2245- }
2246-
2247- g_variant_builder_close(&builder);
2248- g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); /* wait */
2249-
2250- GError* error = nullptr;
2251- auto stop_variant =
2252- g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* Dbus */
2253- DBUS_SERVICE_UPSTART, /* Upstart name */
2254- jobpath.c_str(), /* path */
2255- DBUS_INTERFACE_UPSTART_JOB, /* interface */
2256- "Stop", /* method */
2257- g_variant_builder_end(&builder), /* params */
2258- nullptr, /* return */
2259- G_DBUS_CALL_FLAGS_NONE, /* flags */
2260- -1, /* timeout: default */
2261- registry_->impl->thread.getCancellable().get(), /* cancellable */
2262- &error); /* error (hopefully not) */
2263-
2264- g_clear_pointer(&stop_variant, g_variant_unref);
2265-
2266- if (error != nullptr)
2267- {
2268- g_warning("Unable to stop job %s app_id %s instance_id %s: %s", job_.c_str(),
2269- std::string(appId_).c_str(), instance_.c_str(), error->message);
2270- g_error_free(error);
2271- return false;
2272- }
2273-
2274- return true;
2275- }))
2276- {
2277- g_warning("Unable to stop Upstart instance");
2278- }
2279-}
2280-
2281-/** Create a new Upstart Instance object that can track the job and
2282- get information about it.
2283-
2284- \param appId Application ID
2285- \param job Upstart job name
2286- \param instance Upstart instance name
2287- \param urls URLs sent to the application (only on launch today)
2288- \param registry Registry of persistent connections to use
2289-*/
2290-Upstart::Upstart(const AppID& appId,
2291- const std::string& job,
2292- const std::string& instance,
2293- const std::vector<Application::URL>& urls,
2294- const std::shared_ptr<Registry>& registry)
2295- : Base(appId, job, instance, urls, registry)
2296-{
2297- g_debug("Creating a new Upstart for '%s' instance '%s'", std::string(appId).c_str(), instance.c_str());
2298-}
2299-
2300-/** Small helper that we can new/delete to work better with C stuff */
2301-struct StartCHelper
2302-{
2303- std::shared_ptr<Upstart> ptr;
2304-};
2305-
2306-/** Callback from starting an application. It checks to see whether the
2307- app is already running. If it is already running then we need to send
2308- the URLs to it via DBus.
2309-
2310- \param obj The GDBusConnection object
2311- \param res Async result object
2312- \param user_data A pointer to a StartCHelper structure
2313-*/
2314-void Upstart::application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data)
2315-{
2316- auto data = static_cast<StartCHelper*>(user_data);
2317- GError* error{nullptr};
2318- GVariant* result{nullptr};
2319-
2320- tracepoint(ubuntu_app_launch, libual_start_message_callback, std::string(data->ptr->appId_).c_str());
2321-
2322- g_debug("Started Message Callback: %s", std::string(data->ptr->appId_).c_str());
2323-
2324- result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
2325-
2326- g_clear_pointer(&result, g_variant_unref);
2327-
2328- if (error != nullptr)
2329- {
2330- if (g_dbus_error_is_remote_error(error))
2331- {
2332- gchar* remote_error = g_dbus_error_get_remote_error(error);
2333- g_debug("Remote error: %s", remote_error);
2334- if (g_strcmp0(remote_error, "com.ubuntu.Upstart0_6.Error.AlreadyStarted") == 0)
2335- {
2336- auto urls = urlsToStrv(data->ptr->urls_);
2337- second_exec(data->ptr->registry_->impl->_dbus.get(), /* DBus */
2338- data->ptr->registry_->impl->thread.getCancellable().get(), /* cancellable */
2339- data->ptr->primaryPid(), /* primary pid */
2340- std::string(data->ptr->appId_).c_str(), /* appid */
2341- std::string(data->ptr->instance_).c_str(), /* instance */
2342- urls.get()); /* urls */
2343- }
2344-
2345- g_free(remote_error);
2346- }
2347- else
2348- {
2349- g_warning("Unable to emit event to start application: %s", error->message);
2350- }
2351- g_error_free(error);
2352- }
2353-
2354- delete data;
2355-}
2356-
2357-std::string Upstart::upstartJobPath()
2358-{
2359- auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry_->impl->jobs);
2360- return manager->upstartJobPath(job_);
2361-}
2362-
2363-/** Go through the list of PIDs calling a function and handling
2364- the issue with getting PIDs being a racey condition.
2365-
2366- \param eachPid Function to run on each PID
2367-*/
2368-std::vector<pid_t> Upstart::forAllPids(const std::shared_ptr<Registry>& reg,
2369- const AppID& appid,
2370- const std::string& jobpath,
2371- std::function<void(pid_t)> eachPid)
2372-{
2373- std::set<pid_t> seenPids;
2374- bool added = true;
2375-
2376- while (added)
2377- {
2378- added = false;
2379- auto pidlist = pids(reg, appid, jobpath);
2380- for (auto pid : pidlist)
2381- {
2382- if (seenPids.insert(pid).second)
2383- {
2384- eachPid(pid);
2385- added = true;
2386- }
2387- }
2388- }
2389-
2390- return std::vector<pid_t>(seenPids.begin(), seenPids.end());
2391-}
2392-
2393-/** Pauses this application by sending SIGSTOP to all the PIDs in the
2394- cgroup and tells Zeitgeist that we've left the application. */
2395-void Upstart::pause()
2396-{
2397- g_debug("Pausing application: %s", std::string(appId_).c_str());
2398-
2399- auto registry = registry_;
2400- auto appid = appId_;
2401- auto instance = instance_;
2402- auto jobpath = upstartJobPath();
2403-
2404- registry->impl->thread.executeOnThread([registry, appid, instance, jobpath] {
2405- auto pids = forAllPids(registry, appid, jobpath, [](pid_t pid) {
2406- auto oomval = oom::paused();
2407- g_debug("Pausing PID: %d (%d)", pid, int(oomval));
2408- signalToPid(pid, SIGSTOP);
2409- oomValueToPid(pid, oomval);
2410- });
2411-
2412- pidListToDbus(registry, appid, instance, pids, "ApplicationPaused");
2413- });
2414-
2415- registry_->impl->zgSendEvent(appId_, ZEITGEIST_ZG_LEAVE_EVENT);
2416-}
2417-
2418-/** Resumes this application by sending SIGCONT to all the PIDs in the
2419- cgroup and tells Zeitgeist that we're accessing the application. */
2420-void Upstart::resume()
2421-{
2422- g_debug("Resuming application: %s", std::string(appId_).c_str());
2423-
2424- auto registry = registry_;
2425- auto appid = appId_;
2426- auto instance = instance_;
2427- auto jobpath = upstartJobPath();
2428-
2429- registry->impl->thread.executeOnThread([registry, appid, instance, jobpath] {
2430- auto pids = forAllPids(registry, appid, jobpath, [](pid_t pid) {
2431- auto oomval = oom::focused();
2432- g_debug("Resuming PID: %d (%d)", pid, int(oomval));
2433- signalToPid(pid, SIGCONT);
2434- oomValueToPid(pid, oomval);
2435- });
2436-
2437- pidListToDbus(registry, appid, instance, pids, "ApplicationResumed");
2438- });
2439-
2440- registry_->impl->zgSendEvent(appId_, ZEITGEIST_ZG_ACCESS_EVENT);
2441-}
2442-
2443-std::vector<pid_t> Upstart::pids(const std::shared_ptr<Registry>& reg, const AppID& appid, const std::string& jobpath)
2444-{
2445- auto manager = std::dynamic_pointer_cast<manager::Upstart>(reg->impl->jobs);
2446- auto pids = manager->pidsFromCgroup(jobpath);
2447- g_debug("Got %d PIDs for AppID '%s'", int(pids.size()), std::string(appid).c_str());
2448- return pids;
2449-}
2450-
2451-} // namespace instances
2452-
2453-namespace manager
2454-{
2455-
2456-Upstart::Upstart(std::shared_ptr<Registry> registry)
2457- : Base(registry)
2458-{
2459-}
2460-
2461-Upstart::~Upstart()
2462-{
2463- auto dohandle = [&](guint& handle) {
2464- if (handle != 0)
2465- {
2466- g_dbus_connection_signal_unsubscribe(dbus_.get(), handle);
2467- handle = 0;
2468- }
2469- };
2470-
2471- dohandle(handle_appStarted);
2472- dohandle(handle_appStopped);
2473- dohandle(handle_appFailed);
2474-}
2475-
2476-/** Launch an application and create a new Upstart instance object to track
2477- its progress.
2478-
2479- \param appId Application ID
2480- \param job Upstart job name
2481- \param instance Upstart instance name
2482- \param urls URLs sent to the application (only on launch today)
2483- \param mode Whether or not to setup the environment for testing
2484- \param getenv A function to get additional environment variable when appropriate
2485-*/
2486-std::shared_ptr<Application::Instance> Upstart::launch(
2487- const AppID& appId,
2488- const std::string& job,
2489- const std::string& instance,
2490- const std::vector<Application::URL>& urls,
2491- launchMode mode,
2492- std::function<std::list<std::pair<std::string, std::string>>(void)>& getenv)
2493-{
2494- if (appId.empty())
2495- return {};
2496-
2497- auto registry = registry_.lock();
2498-
2499- if (!registry)
2500- {
2501- g_warning("Registry object invalid!");
2502- return {};
2503- }
2504-
2505- return registry->impl->thread.executeOnThread<std::shared_ptr<instance::Upstart>>(
2506- [&]() -> std::shared_ptr<instance::Upstart> {
2507- auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry->impl->jobs);
2508- std::string appIdStr{appId};
2509- g_debug("Initializing params for an new instance::Upstart for: %s", appIdStr.c_str());
2510-
2511- tracepoint(ubuntu_app_launch, libual_start, appIdStr.c_str());
2512-
2513- int timeout = 1;
2514- if (ubuntu::app_launch::Registry::Impl::isWatchingAppStarting())
2515- {
2516- timeout = 0;
2517- }
2518-
2519- auto handshake = starting_handshake_start(appIdStr.c_str(), instance.c_str(), timeout);
2520- if (handshake == nullptr)
2521- {
2522- g_warning("Unable to setup starting handshake");
2523- }
2524-
2525- /* Figure out the DBus path for the job */
2526- auto jobpath = manager->upstartJobPath(job);
2527-
2528- /* Build up our environment */
2529- auto env = getenv();
2530-
2531- env.emplace_back(std::make_pair("APP_ID", appIdStr)); /* Application ID */
2532- env.emplace_back(std::make_pair("APP_LAUNCHER_PID", std::to_string(getpid()))); /* Who we are, for bugs */
2533-
2534- if (!urls.empty())
2535- {
2536- auto accumfunc = [](const std::string& prev, Application::URL thisurl) -> std::string {
2537- gchar* gescaped = g_shell_quote(thisurl.value().c_str());
2538- std::string escaped;
2539- if (gescaped != nullptr)
2540- {
2541- escaped = gescaped;
2542- g_free(gescaped);
2543- }
2544- else
2545- {
2546- g_warning("Unable to escape URL: %s", thisurl.value().c_str());
2547- return prev;
2548- }
2549-
2550- if (prev.empty())
2551- {
2552- return escaped;
2553- }
2554- else
2555- {
2556- return prev + " " + escaped;
2557- }
2558- };
2559- auto urlstring = std::accumulate(urls.begin(), urls.end(), std::string{}, accumfunc);
2560- env.emplace_back(std::make_pair("APP_URIS", urlstring));
2561- }
2562-
2563- if (mode == launchMode::TEST)
2564- {
2565- env.emplace_back(std::make_pair("QT_LOAD_TESTABILITY", "1"));
2566- }
2567-
2568- /* Convert to GVariant */
2569- GVariantBuilder builder;
2570- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
2571-
2572- g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
2573-
2574- for (const auto& envvar : env)
2575- {
2576- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf(
2577- "%s=%s", envvar.first.c_str(), envvar.second.c_str())));
2578- }
2579-
2580- g_variant_builder_close(&builder);
2581- g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
2582-
2583- auto retval = std::make_shared<instance::Upstart>(appId, job, instance, urls, registry);
2584- auto chelper = new instance::StartCHelper{};
2585- chelper->ptr = retval;
2586-
2587- tracepoint(ubuntu_app_launch, handshake_wait, appIdStr.c_str());
2588- starting_handshake_wait(handshake);
2589- tracepoint(ubuntu_app_launch, handshake_complete, appIdStr.c_str());
2590-
2591- /* Call the job start function */
2592- g_debug("Asking Upstart to start task for: %s", appIdStr.c_str());
2593- g_dbus_connection_call(registry->impl->_dbus.get(), /* bus */
2594- DBUS_SERVICE_UPSTART, /* service name */
2595- jobpath.c_str(), /* Path */
2596- DBUS_INTERFACE_UPSTART_JOB, /* interface */
2597- "Start", /* method */
2598- g_variant_builder_end(&builder), /* params */
2599- nullptr, /* return */
2600- G_DBUS_CALL_FLAGS_NONE, /* flags */
2601- -1, /* default timeout */
2602- registry->impl->thread.getCancellable().get(), /* cancellable */
2603- instance::Upstart::application_start_cb, /* callback */
2604- chelper /* object */
2605- );
2606-
2607- tracepoint(ubuntu_app_launch, libual_start_message_sent, appIdStr.c_str());
2608-
2609- return retval;
2610- });
2611-}
2612-
2613-/** Special characters that could be an application name that
2614- would activate in a regex */
2615-const static std::regex regexCharacters("([\\.\\-])");
2616-
2617-std::shared_ptr<Application::Instance> Upstart::existing(const AppID& appId,
2618- const std::string& job,
2619- const std::string& instance,
2620- const std::vector<Application::URL>& urls)
2621-{
2622- return std::make_shared<instance::Upstart>(appId, job, instance, urls, registry_.lock());
2623-}
2624-
2625-std::vector<std::shared_ptr<instance::Base>> Upstart::instances(const AppID& appID, const std::string& job)
2626-{
2627- std::vector<std::shared_ptr<instance::Base>> vect;
2628- auto startsWith = std::string(appID);
2629- if (job != "application-click")
2630- {
2631- startsWith += "-";
2632- }
2633-
2634- auto regexstr =
2635- std::string{"^(?:"} + std::regex_replace(startsWith, regexCharacters, "\\$&") + std::string{")(\\d*)$"};
2636- auto instanceRegex = std::regex(regexstr);
2637-
2638- for (auto instance : upstartInstancesForJob(job))
2639- {
2640- std::smatch instanceMatch;
2641- g_debug("Looking at job '%s' instance: %s", job.c_str(), instance.c_str());
2642- if (std::regex_match(instance, instanceMatch, instanceRegex))
2643- {
2644- auto app = existing(appID, job, instanceMatch[1].str(), {});
2645- vect.emplace_back(std::dynamic_pointer_cast<instance::Base>(app));
2646- }
2647- }
2648-
2649- g_debug("App '%s' has %d instances", std::string(appID).c_str(), int(vect.size()));
2650-
2651- return vect;
2652-}
2653-
2654-/** Structure to track the data needed for upstart events. This cleans
2655- up the lifecycle as we're passing this as a pointer through the
2656- GLib calls. */
2657-struct upstartEventData
2658-{
2659- /** Keeping a weak pointer because the handle is held by
2660- the registry implementation. */
2661- std::weak_ptr<Registry> weakReg;
2662-};
2663-
2664-/** Regex to parse the JOB environment variable from Upstart */
2665-const std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"};
2666-/** Regex to parse the INSTANCE environment variable from Upstart */
2667-const std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"};
2668-
2669-/** Core of most of the events that come from Upstart directly. Includes parsing of the
2670- Upstart event environment and calling the appropriate signal with the right Application
2671- object and eventually its instance */
2672-void Upstart::upstartEventEmitted(
2673- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal,
2674- std::shared_ptr<GVariant> params,
2675- const std::shared_ptr<Registry>& reg)
2676-{
2677- std::string jobname;
2678- std::string sappid;
2679- std::string instance;
2680-
2681- gchar* env = nullptr;
2682- auto envs = g_variant_get_child_value(params.get(), 1);
2683- GVariantIter iter;
2684- g_variant_iter_init(&iter, envs);
2685-
2686- while (g_variant_iter_loop(&iter, "s", &env))
2687- {
2688- std::smatch match;
2689- std::string senv = env;
2690-
2691- if (std::regex_match(senv, match, jobenv_regex))
2692- {
2693- jobname = match[1].str();
2694- }
2695- else if (std::regex_match(senv, match, instanceenv_regex))
2696- {
2697- sappid = match[1].str();
2698- instance = match[2].str();
2699- }
2700- }
2701-
2702- g_variant_unref(envs);
2703-
2704- if (jobname.empty())
2705- {
2706- return;
2707- }
2708-
2709- g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str());
2710-
2711- auto appid = AppID::find(reg, sappid);
2712- auto app = Application::create(appid, reg);
2713- auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instance);
2714-
2715- signal(app, inst);
2716-}
2717-
2718-/** Grab the signal object for application startup. If we're not already listing for
2719- those signals this sets up a listener for them. */
2720-core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Upstart::appStarted()
2721-{
2722- std::call_once(flag_appStarted, [this]() {
2723- auto reg = registry_.lock();
2724-
2725- reg->impl->thread.executeOnThread<bool>([this, reg]() {
2726- upstartEventData* data = new upstartEventData{reg};
2727-
2728- handle_appStarted = g_dbus_connection_signal_subscribe(
2729- reg->impl->_dbus.get(), /* bus */
2730- nullptr, /* sender */
2731- DBUS_INTERFACE_UPSTART, /* interface */
2732- "EventEmitted", /* signal */
2733- DBUS_PATH_UPSTART, /* path */
2734- "started", /* arg0 */
2735- G_DBUS_SIGNAL_FLAGS_NONE,
2736- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
2737- gpointer user_data) {
2738- auto data = static_cast<upstartEventData*>(user_data);
2739- auto reg = data->weakReg.lock();
2740-
2741- if (!reg)
2742- {
2743- g_warning("Registry object invalid!");
2744- return;
2745- }
2746-
2747- auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
2748- auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs);
2749- upstart->upstartEventEmitted(upstart->sig_appStarted, sparams, reg);
2750- }, /* callback */
2751- data, /* user data */
2752- [](gpointer user_data) {
2753- auto data = static_cast<upstartEventData*>(user_data);
2754- delete data;
2755- }); /* user data destroy */
2756-
2757- return true;
2758- });
2759- });
2760-
2761- return sig_appStarted;
2762-}
2763-
2764-/** Grab the signal object for application stopping. If we're not already listing for
2765- those signals this sets up a listener for them. */
2766-core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Upstart::appStopped()
2767-{
2768- std::call_once(flag_appStopped, [this]() {
2769- auto reg = registry_.lock();
2770-
2771- reg->impl->thread.executeOnThread<bool>([this, reg]() {
2772- upstartEventData* data = new upstartEventData{reg};
2773-
2774- handle_appStopped = g_dbus_connection_signal_subscribe(
2775- reg->impl->_dbus.get(), /* bus */
2776- nullptr, /* sender */
2777- DBUS_INTERFACE_UPSTART, /* interface */
2778- "EventEmitted", /* signal */
2779- DBUS_PATH_UPSTART, /* path */
2780- "stopped", /* arg0 */
2781- G_DBUS_SIGNAL_FLAGS_NONE,
2782- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
2783- gpointer user_data) {
2784- auto data = static_cast<upstartEventData*>(user_data);
2785- auto reg = data->weakReg.lock();
2786-
2787- if (!reg)
2788- {
2789- g_warning("Registry object invalid!");
2790- return;
2791- }
2792-
2793- auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
2794- auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs);
2795- upstart->upstartEventEmitted(upstart->sig_appStopped, sparams, reg);
2796- }, /* callback */
2797- data, /* user data */
2798- [](gpointer user_data) {
2799- auto data = static_cast<upstartEventData*>(user_data);
2800- delete data;
2801- }); /* user data destroy */
2802-
2803- return true;
2804- });
2805- });
2806-
2807- return sig_appStopped;
2808-}
2809-
2810-/** Grab the signal object for application failing. If we're not already listing for
2811- those signals this sets up a listener for them. */
2812-core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>&
2813- Upstart::appFailed()
2814-{
2815- std::call_once(flag_appFailed, [this]() {
2816- auto reg = registry_.lock();
2817-
2818- reg->impl->thread.executeOnThread<bool>([this, reg]() {
2819- upstartEventData* data = new upstartEventData{reg};
2820-
2821- handle_appFailed = g_dbus_connection_signal_subscribe(
2822- reg->impl->_dbus.get(), /* bus */
2823- nullptr, /* sender */
2824- "com.canonical.UbuntuAppLaunch", /* interface */
2825- "ApplicationFailed", /* signal */
2826- "/", /* path */
2827- nullptr, /* arg0 */
2828- G_DBUS_SIGNAL_FLAGS_NONE,
2829- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
2830- gpointer user_data) {
2831- auto data = static_cast<upstartEventData*>(user_data);
2832- auto reg = data->weakReg.lock();
2833-
2834- if (!reg)
2835- {
2836- g_warning("Registry object invalid!");
2837- return;
2838- }
2839-
2840- const gchar* sappid = nullptr;
2841- const gchar* sinstid = nullptr;
2842- const gchar* typestr = nullptr;
2843-
2844- Registry::FailureType type = Registry::FailureType::CRASH;
2845- g_variant_get(params, "(&s&s&s)", &sappid, &sinstid, &typestr);
2846-
2847- if (g_strcmp0("crash", typestr) == 0)
2848- {
2849- type = Registry::FailureType::CRASH;
2850- }
2851- else if (g_strcmp0("start-failure", typestr) == 0)
2852- {
2853- type = Registry::FailureType::START_FAILURE;
2854- }
2855- else
2856- {
2857- g_warning("Application failure type '%s' unknown, reporting as a crash", typestr);
2858- }
2859-
2860- auto appid = AppID::find(reg, sappid);
2861- auto app = Application::create(appid, reg);
2862- auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(sinstid);
2863-
2864- auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs);
2865- upstart->sig_appFailed(app, {}, type);
2866- }, /* callback */
2867- data, /* user data */
2868- [](gpointer user_data) {
2869- auto data = static_cast<upstartEventData*>(user_data);
2870- delete data;
2871- }); /* user data destroy */
2872-
2873- return true;
2874- });
2875- });
2876-
2877- return sig_appFailed;
2878-}
2879-
2880-/** Initialize the CGManager connection, including a timeout to disconnect
2881- as CGManager doesn't free resources entirely well. So it's better if
2882- we connect and disconnect occationally */
2883-void Upstart::initCGManager()
2884-{
2885- if (cgManager_)
2886- return;
2887-
2888- auto registry = registry_.lock();
2889-
2890- cgManager_ = registry->impl->thread.executeOnThread<std::shared_ptr<GDBusConnection>>([this, registry]() {
2891- bool use_session_bus = g_getenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS") != nullptr;
2892- if (use_session_bus)
2893- {
2894- /* For working dbusmock */
2895- g_debug("Connecting to CG Manager on session bus");
2896- return registry->impl->_dbus;
2897- }
2898-
2899- auto cancel =
2900- std::shared_ptr<GCancellable>(g_cancellable_new(), [](GCancellable* cancel) { g_clear_object(&cancel); });
2901-
2902- /* Ensure that we do not wait for more than a second */
2903- registry->impl->thread.timeoutSeconds(std::chrono::seconds{1},
2904- [cancel]() { g_cancellable_cancel(cancel.get()); });
2905-
2906- GError* error = nullptr;
2907- auto retval = std::shared_ptr<GDBusConnection>(
2908- g_dbus_connection_new_for_address_sync(CGMANAGER_DBUS_PATH, /* cgmanager path */
2909- G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, /* flags */
2910- nullptr, /* Auth Observer */
2911- cancel.get(), /* Cancellable */
2912- &error),
2913- [](GDBusConnection* con) { g_clear_object(&con); });
2914-
2915- if (error != nullptr)
2916- {
2917- g_warning("Unable to get CGManager connection: %s", error->message);
2918- g_error_free(error);
2919- }
2920-
2921- return retval;
2922- });
2923-
2924- /* NOTE: This will execute on the thread */
2925- registry->impl->thread.timeoutSeconds(std::chrono::seconds{10}, [this]() { cgManager_.reset(); });
2926-}
2927-
2928-/** Get a list of PIDs from a CGroup, uses the CGManager connection to list
2929- all of the PIDs. It is important to note that this is an IPC call, so it can
2930- by its nature, be racy. Once the message has been sent the group can change.
2931- You should take that into account in your usage of it. */
2932-std::vector<pid_t> Upstart::pidsFromCgroup(const std::string& jobpath)
2933-{
2934- initCGManager();
2935- auto lmanager = cgManager_; /* Grab a local copy so we ensure it lasts through our lifetime */
2936- auto registry = registry_.lock();
2937-
2938- return registry->impl->thread.executeOnThread<std::vector<pid_t>>([&jobpath, lmanager]() -> std::vector<pid_t> {
2939- GError* error = nullptr;
2940- const gchar* name = g_getenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME");
2941- std::string groupname;
2942- if (!jobpath.empty())
2943- {
2944- groupname = "upstart/" + jobpath;
2945- }
2946-
2947- g_debug("Looking for cg manager '%s' group '%s'", name, groupname.c_str());
2948-
2949- auto vtpids = g_dbus_connection_call_sync(
2950- lmanager.get(), /* connection */
2951- name, /* bus name for direct connection is nullptr */
2952- "/org/linuxcontainers/cgmanager", /* object */
2953- "org.linuxcontainers.cgmanager0_0", /* interface */
2954- "GetTasksRecursive", /* method */
2955- g_variant_new("(ss)", "freezer", groupname.empty() ? "" : groupname.c_str()), /* params */
2956- G_VARIANT_TYPE("(ai)"), /* output */
2957- G_DBUS_CALL_FLAGS_NONE, /* flags */
2958- -1, /* default timeout */
2959- nullptr, /* cancellable */
2960- &error); /* error */
2961-
2962- if (error != nullptr)
2963- {
2964- g_warning("Unable to get PID list from cgroup manager: %s", error->message);
2965- g_error_free(error);
2966- return {};
2967- }
2968-
2969- auto vpids = g_variant_get_child_value(vtpids, 0);
2970- GVariantIter iter;
2971- g_variant_iter_init(&iter, vpids);
2972- gint32 pid;
2973- std::vector<pid_t> pids;
2974-
2975- while (g_variant_iter_loop(&iter, "i", &pid))
2976- {
2977- pids.push_back(pid);
2978- }
2979-
2980- g_variant_unref(vpids);
2981- g_variant_unref(vtpids);
2982-
2983- return pids;
2984- });
2985-}
2986-
2987-/** Looks to find the Upstart object path for a specific Upstart job. This first
2988- checks the cache, and otherwise does the lookup on DBus. */
2989-std::string Upstart::upstartJobPath(const std::string& job)
2990-{
2991- try
2992- {
2993- return upstartJobPathCache_.at(job);
2994- }
2995- catch (std::out_of_range& e)
2996- {
2997- auto registry = registry_.lock();
2998- auto path = registry->impl->thread.executeOnThread<std::string>([this, &job, &registry]() -> std::string {
2999- GError* error = nullptr;
3000- auto job_path_variant =
3001- g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */
3002- DBUS_SERVICE_UPSTART, /* service */
3003- DBUS_PATH_UPSTART, /* path */
3004- DBUS_INTERFACE_UPSTART, /* iface */
3005- "GetJobByName", /* method */
3006- g_variant_new("(s)", job.c_str()), /* params */
3007- G_VARIANT_TYPE("(o)"), /* return */
3008- G_DBUS_CALL_FLAGS_NONE, /* flags */
3009- -1, /* timeout: default */
3010- registry->impl->thread.getCancellable().get(), /* cancellable */
3011- &error); /* error */
3012-
3013- if (error != nullptr)
3014- {
3015- g_warning("Unable to find job '%s': %s", job.c_str(), error->message);
3016- g_error_free(error);
3017- return {};
3018- }
3019-
3020- gchar* job_path = nullptr;
3021- g_variant_get(job_path_variant, "(o)", &job_path);
3022- g_variant_unref(job_path_variant);
3023-
3024- if (job_path != nullptr)
3025- {
3026- std::string path(job_path);
3027- g_free(job_path);
3028- return path;
3029- }
3030- else
3031- {
3032- return {};
3033- }
3034- });
3035-
3036- upstartJobPathCache_[job] = path;
3037- return path;
3038- }
3039-}
3040-
3041-/** Queries Upstart to get all the instances of a given job. This
3042- can take a while as the number of dbus calls is n+1. It is
3043- rare that apps have many instances though. */
3044-std::list<std::string> Upstart::upstartInstancesForJob(const std::string& job)
3045-{
3046- std::string jobpath = upstartJobPath(job);
3047- if (jobpath.empty())
3048- {
3049- return {};
3050- }
3051-
3052- auto registry = registry_.lock();
3053- return registry->impl->thread.executeOnThread<std::list<std::string>>(
3054- [this, &job, &jobpath, &registry]() -> std::list<std::string> {
3055- GError* error = nullptr;
3056- auto instance_tuple =
3057- g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */
3058- DBUS_SERVICE_UPSTART, /* service */
3059- jobpath.c_str(), /* object path */
3060- DBUS_INTERFACE_UPSTART_JOB, /* iface */
3061- "GetAllInstances", /* method */
3062- nullptr, /* params */
3063- G_VARIANT_TYPE("(ao)"), /* return type */
3064- G_DBUS_CALL_FLAGS_NONE, /* flags */
3065- -1, /* timeout: default */
3066- registry->impl->thread.getCancellable().get(), /* cancellable */
3067- &error);
3068-
3069- if (error != nullptr)
3070- {
3071- g_warning("Unable to get instances of job '%s': %s", job.c_str(), error->message);
3072- g_error_free(error);
3073- return {};
3074- }
3075-
3076- if (instance_tuple == nullptr)
3077- {
3078- return {};
3079- }
3080-
3081- auto instance_list = g_variant_get_child_value(instance_tuple, 0);
3082- g_variant_unref(instance_tuple);
3083-
3084- GVariantIter instance_iter;
3085- g_variant_iter_init(&instance_iter, instance_list);
3086- const gchar* instance_path = nullptr;
3087- std::list<std::string> instances;
3088-
3089- while (g_variant_iter_loop(&instance_iter, "&o", &instance_path))
3090- {
3091- auto props_tuple =
3092- g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */
3093- DBUS_SERVICE_UPSTART, /* service */
3094- instance_path, /* object path */
3095- "org.freedesktop.DBus.Properties", /* interface */
3096- "GetAll", /* method */
3097- g_variant_new("(s)", DBUS_INTERFACE_UPSTART_INSTANCE), /* params */
3098- G_VARIANT_TYPE("(a{sv})"), /* return type */
3099- G_DBUS_CALL_FLAGS_NONE, /* flags */
3100- -1, /* timeout: default */
3101- registry->impl->thread.getCancellable().get(), /* cancellable */
3102- &error);
3103-
3104- if (error != nullptr)
3105- {
3106- g_warning("Unable to name of instance '%s': %s", instance_path, error->message);
3107- g_error_free(error);
3108- error = nullptr;
3109- continue;
3110- }
3111-
3112- auto props_dict = g_variant_get_child_value(props_tuple, 0);
3113-
3114- auto namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
3115- if (namev != nullptr)
3116- {
3117- auto name = g_variant_get_string(namev, nullptr);
3118- g_debug("Adding instance for job '%s': %s", job.c_str(), name);
3119- instances.push_back(name);
3120- g_variant_unref(namev);
3121- }
3122-
3123- g_variant_unref(props_dict);
3124- g_variant_unref(props_tuple);
3125- }
3126-
3127- g_variant_unref(instance_list);
3128-
3129- return instances;
3130- });
3131-}
3132-
3133-std::list<std::shared_ptr<Application>> Upstart::runningApps()
3134-{
3135- std::list<std::string> instances;
3136-
3137- /* Get all the legacy instances */
3138- instances.splice(instances.begin(), upstartInstancesForJob("application-legacy"));
3139- /* Get all the snap instances */
3140- instances.splice(instances.begin(), upstartInstancesForJob("application-snap"));
3141-
3142- /* Remove the instance ID */
3143- std::transform(instances.begin(), instances.end(), instances.begin(), [](std::string& instancename) -> std::string {
3144- static const std::regex instanceregex("^(.*)-[0-9]*$");
3145- std::smatch match;
3146- if (std::regex_match(instancename, match, instanceregex))
3147- {
3148- return match[1].str();
3149- }
3150- else
3151- {
3152- g_warning("Unable to match instance name: %s", instancename.c_str());
3153- return {};
3154- }
3155- });
3156-
3157- /* Deduplicate Set */
3158- std::set<std::string> instanceset;
3159- for (auto instance : instances)
3160- {
3161- if (!instance.empty())
3162- instanceset.insert(instance);
3163- }
3164-
3165- /* Add in the click instances */
3166- for (auto instance : upstartInstancesForJob("application-click"))
3167- {
3168- instanceset.insert(instance);
3169- }
3170-
3171- g_debug("Overall there are %d instances: %s", int(instanceset.size()),
3172- std::accumulate(instanceset.begin(), instanceset.end(), std::string{}, [](const std::string& instr,
3173- std::string instance) {
3174- return instr.empty() ? instance : instr + ", " + instance;
3175- }).c_str());
3176-
3177- /* Convert to Applications */
3178- auto registry = registry_.lock();
3179- std::list<std::shared_ptr<Application>> apps;
3180- for (auto instance : instanceset)
3181- {
3182- auto appid = AppID::find(registry, instance);
3183- auto app = Application::create(appid, registry);
3184- apps.push_back(app);
3185- }
3186-
3187- return apps;
3188-}
3189-
3190-} // namespace manager
3191-} // namespace jobs
3192-} // namespace app_launch
3193-} // namespace ubuntu
3194
3195=== removed file 'libubuntu-app-launch/jobs-upstart.h'
3196--- libubuntu-app-launch/jobs-upstart.h 2017-01-11 22:16:14 +0000
3197+++ libubuntu-app-launch/jobs-upstart.h 1970-01-01 00:00:00 +0000
3198@@ -1,101 +0,0 @@
3199-/*
3200- * Copyright © 2016 Canonical Ltd.
3201- *
3202- * This program is free software: you can redistribute it and/or modify it
3203- * under the terms of the GNU General Public License version 3, as published
3204- * by the Free Software Foundation.
3205- *
3206- * This program is distributed in the hope that it will be useful, but
3207- * WITHOUT ANY WARRANTY; without even the implied warranties of
3208- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
3209- * PURPOSE. See the GNU General Public License for more details.
3210- *
3211- * You should have received a copy of the GNU General Public License along
3212- * with this program. If not, see <http://www.gnu.org/licenses/>.
3213- *
3214- * Authors:
3215- * Ted Gould <ted.gould@canonical.com>
3216- */
3217-
3218-#pragma once
3219-
3220-#include "jobs-base.h"
3221-#include <gio/gio.h>
3222-#include <map>
3223-
3224-namespace ubuntu
3225-{
3226-namespace app_launch
3227-{
3228-namespace jobs
3229-{
3230-namespace manager
3231-{
3232-
3233-class Upstart : public Base
3234-{
3235-public:
3236- Upstart(std::shared_ptr<Registry> registry);
3237- virtual ~Upstart();
3238-
3239- virtual std::shared_ptr<Application::Instance> launch(
3240- const AppID& appId,
3241- const std::string& job,
3242- const std::string& instance,
3243- const std::vector<Application::URL>& urls,
3244- launchMode mode,
3245- std::function<std::list<std::pair<std::string, std::string>>(void)>& getenv) override;
3246- virtual std::shared_ptr<Application::Instance> existing(const AppID& appId,
3247- const std::string& job,
3248- const std::string& instance,
3249- const std::vector<Application::URL>& urls) override;
3250-
3251- virtual std::list<std::shared_ptr<Application>> runningApps() override;
3252-
3253- virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) override;
3254-
3255- /* Signals to apps */
3256- virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
3257- appStarted() override;
3258- virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
3259- appStopped() override;
3260- virtual core::Signal<const std::shared_ptr<Application>&,
3261- const std::shared_ptr<Application::Instance>&,
3262- Registry::FailureType>&
3263- appFailed() override;
3264-
3265- std::vector<pid_t> pidsFromCgroup(const std::string& jobpath);
3266-
3267- std::list<std::string> upstartInstancesForJob(const std::string& job);
3268- std::string upstartJobPath(const std::string& job);
3269-
3270-private:
3271- void initCGManager();
3272-
3273- std::shared_ptr<GDBusConnection> cgManager_;
3274-
3275- /** Getting the Upstart job path is relatively expensive in
3276- that it requires a DBus call. Worth keeping a cache of. */
3277- std::map<std::string, std::string> upstartJobPathCache_;
3278-
3279- guint handle_appStarted{0}; /**< GDBus signal watcher handle for app started signal */
3280- guint handle_appStopped{0}; /**< GDBus signal watcher handle for app stopped signal */
3281- guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */
3282-
3283- std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application
3284- started */
3285- std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application
3286- stopped */
3287- std::once_flag
3288- flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */
3289-
3290- void upstartEventEmitted(
3291- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal,
3292- std::shared_ptr<GVariant> params,
3293- const std::shared_ptr<Registry>& reg);
3294-};
3295-
3296-} // namespace manager
3297-} // namespace jobs
3298-} // namespace app_launch
3299-} // namespace ubuntu
3300
3301=== modified file 'libubuntu-app-launch/registry.cpp'
3302--- libubuntu-app-launch/registry.cpp 2017-01-11 22:16:14 +0000
3303+++ libubuntu-app-launch/registry.cpp 2017-02-22 21:41:30 +0000
3304@@ -31,8 +31,6 @@
3305 #include "application-impl-snap.h"
3306 #endif
3307
3308-#include "helper-impl-click.h"
3309-
3310 namespace ubuntu
3311 {
3312 namespace app_launch
3313@@ -71,13 +69,14 @@
3314 return list;
3315 }
3316
3317-std::list<std::shared_ptr<Helper>> Registry::runningHelpers(Helper::Type type, std::shared_ptr<Registry> connection)
3318+std::list<std::shared_ptr<Helper>> Registry::runningHelpers(Helper::Type type, std::shared_ptr<Registry> registry)
3319 {
3320- std::list<std::shared_ptr<Helper>> list;
3321-
3322- list.splice(list.begin(), helper_impls::Click::running(type, connection));
3323-
3324- return list;
3325+ if (!registry->impl->jobs)
3326+ {
3327+ registry->impl->jobs = jobs::manager::Base::determineFactory(registry);
3328+ }
3329+
3330+ return registry->impl->jobs->runningHelpers(type);
3331 }
3332
3333 /* Quick little helper to bundle up standard code */
3334@@ -160,5 +159,26 @@
3335 return reg->impl->jobs->appResumed();
3336 }
3337
3338+core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& Registry::helperStarted(
3339+ Helper::Type type, const std::shared_ptr<Registry>& reg)
3340+{
3341+ setJobs(reg);
3342+ return reg->impl->jobs->helperStarted(type);
3343+}
3344+
3345+core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& Registry::helperStopped(
3346+ Helper::Type type, const std::shared_ptr<Registry>& reg)
3347+{
3348+ setJobs(reg);
3349+ return reg->impl->jobs->helperStopped(type);
3350+}
3351+
3352+core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&, Registry::FailureType>&
3353+ Registry::helperFailed(Helper::Type type, const std::shared_ptr<Registry>& reg)
3354+{
3355+ setJobs(reg);
3356+ return reg->impl->jobs->helperFailed(type);
3357+}
3358+
3359 } // namespace app_launch
3360 } // namespace ubuntu
3361
3362=== modified file 'libubuntu-app-launch/registry.h'
3363--- libubuntu-app-launch/registry.h 2017-01-24 00:09:09 +0000
3364+++ libubuntu-app-launch/registry.h 2017-02-22 21:41:30 +0000
3365@@ -214,6 +214,37 @@
3366 static std::list<std::shared_ptr<Helper>> runningHelpers(Helper::Type type,
3367 std::shared_ptr<Registry> registry = getDefault());
3368
3369+ /** Get the signal object that is signaled when helper has been
3370+ started.
3371+
3372+ \note This signal handler is activated on the UAL thread
3373+
3374+ \param type Helper type string
3375+ \param reg Registry to get the handler from
3376+ */
3377+ static core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& helperStarted(
3378+ Helper::Type type, const std::shared_ptr<Registry>& reg = getDefault());
3379+
3380+ /** Get the signal object that is signaled when a helper has stopped.
3381+
3382+ \note This signal handler is activated on the UAL thread
3383+
3384+ \param type Helper type string
3385+ \param reg Registry to get the handler from
3386+ */
3387+ static core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& helperStopped(
3388+ Helper::Type type, const std::shared_ptr<Registry>& reg = getDefault());
3389+
3390+ /** Get the signal object that is signaled when a helper has failed.
3391+
3392+ \note This signal handler is activated on the UAL thread
3393+
3394+ \param type Helper type string
3395+ \param reg Registry to get the handler from
3396+ */
3397+ static core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&, FailureType>&
3398+ helperFailed(Helper::Type type, const std::shared_ptr<Registry>& reg = getDefault());
3399+
3400 /* Default Junk */
3401 /** Use the Registry as a global singleton, this function will create
3402 a Registry object if one doesn't exist. Use of this function is
3403
3404=== modified file 'libubuntu-app-launch/ubuntu-app-launch.cpp'
3405--- libubuntu-app-launch/ubuntu-app-launch.cpp 2017-02-02 15:09:59 +0000
3406+++ libubuntu-app-launch/ubuntu-app-launch.cpp 2017-02-22 21:41:30 +0000
3407@@ -37,78 +37,22 @@
3408 /* C++ Interface */
3409 #include "application.h"
3410 #include "appid.h"
3411+#include "helper-impl.h"
3412 #include "registry.h"
3413 #include "registry-impl.h"
3414 #include <algorithm>
3415
3416-static void free_helper (gpointer value);
3417-int kill (pid_t pid, int signal) noexcept;
3418-static gchar * escape_dbus_string (const gchar * input);
3419-
3420-G_DEFINE_QUARK(UBUNTU_APP_LAUNCH_PROXY_PATH, proxy_path)
3421-G_DEFINE_QUARK(UBUNTU_APP_LAUNCH_MIR_FD, mir_fd)
3422-
3423-/* Function to take the urls and escape them so that they can be
3424- parsed on the other side correctly. */
3425-static gchar *
3426-app_uris_string (const gchar * const * uris)
3427-{
3428- guint i = 0;
3429- GArray * array = g_array_new(TRUE, TRUE, sizeof(gchar *));
3430- g_array_set_clear_func(array, free_helper);
3431-
3432- for (i = 0; i < g_strv_length((gchar**)uris); i++) {
3433- gchar * escaped = g_shell_quote(uris[i]);
3434- g_array_append_val(array, escaped);
3435- }
3436-
3437- gchar * urisjoin = g_strjoinv(" ", (gchar**)array->data);
3438- g_array_unref(array);
3439-
3440- return urisjoin;
3441-}
3442-
3443-/* Get the path of the job from Upstart, if we've got it already, we'll just
3444- use the cache of the value */
3445-static const gchar *
3446-get_jobpath (GDBusConnection * con, const gchar * jobname)
3447-{
3448- gchar * cachepath = g_strdup_printf("ubuntu-app-lauch-job-path-cache-%s", jobname);
3449- gpointer cachedata = g_object_get_data(G_OBJECT(con), cachepath);
3450-
3451- if (cachedata != NULL) {
3452- g_free(cachepath);
3453- return (const gchar*)cachedata;
3454- }
3455-
3456- GError * error = NULL;
3457- GVariant * job_path_variant = g_dbus_connection_call_sync(con,
3458- DBUS_SERVICE_UPSTART,
3459- DBUS_PATH_UPSTART,
3460- DBUS_INTERFACE_UPSTART,
3461- "GetJobByName",
3462- g_variant_new("(s)", jobname),
3463- G_VARIANT_TYPE("(o)"),
3464- G_DBUS_CALL_FLAGS_NONE,
3465- -1, /* timeout: default */
3466- NULL, /* cancellable */
3467- &error);
3468-
3469- if (error != NULL) {
3470- g_warning("Unable to find job '%s': %s", jobname, error->message);
3471- g_error_free(error);
3472- g_free(cachepath);
3473- return NULL;
3474- }
3475-
3476- gchar * job_path = NULL;
3477- g_variant_get(job_path_variant, "(o)", &job_path);
3478- g_variant_unref(job_path_variant);
3479-
3480- g_object_set_data_full(G_OBJECT(con), cachepath, job_path, g_free);
3481- g_free(cachepath);
3482-
3483- return job_path;
3484+/* Make a typed string vector out of a GStrv */
3485+template <typename T>
3486+static std::vector<T> uriVector (const gchar * const * uris)
3487+{
3488+ std::vector<T> urivect;
3489+
3490+ for (auto i = 0; uris != nullptr && uris[i] != nullptr; i++) {
3491+ urivect.emplace_back(T::from_raw(uris[i]));
3492+ }
3493+
3494+ return urivect;
3495 }
3496
3497 gboolean
3498@@ -119,11 +63,9 @@
3499 auto appId = ubuntu::app_launch::AppID::find(appid);
3500 auto app = ubuntu::app_launch::Application::create(appId, registry);
3501
3502- std::vector<ubuntu::app_launch::Application::URL> urivect;
3503- for (auto i = 0; uris != nullptr && uris[i] != nullptr; i++)
3504- urivect.emplace_back(ubuntu::app_launch::Application::URL::from_raw(uris[i]));
3505+ auto uriv = uriVector<ubuntu::app_launch::Application::URL>(uris);
3506
3507- auto instance = app->launch(urivect);
3508+ auto instance = app->launch(uriv);
3509
3510 if (instance) {
3511 return TRUE;
3512@@ -144,11 +86,9 @@
3513 auto appId = ubuntu::app_launch::AppID::find(appid);
3514 auto app = ubuntu::app_launch::Application::create(appId, registry);
3515
3516- std::vector<ubuntu::app_launch::Application::URL> urivect;
3517- for (auto i = 0; uris != nullptr && uris[i] != nullptr; i++)
3518- urivect.emplace_back(ubuntu::app_launch::Application::URL::from_raw(uris[i]));
3519+ auto uriv = uriVector<ubuntu::app_launch::Application::URL>(uris);
3520
3521- auto instance = app->launchTest(urivect);
3522+ auto instance = app->launchTest(uriv);
3523
3524 if (instance) {
3525 return TRUE;
3526@@ -161,13 +101,6 @@
3527 }
3528 }
3529
3530-static void
3531-free_helper (gpointer value)
3532-{
3533- gchar ** strp = (gchar **)value;
3534- g_free(*strp);
3535-}
3536-
3537 gboolean
3538 ubuntu_app_launch_stop_application (const gchar * appid)
3539 {
3540@@ -232,46 +165,6 @@
3541 }
3542 }
3543
3544-static GDBusConnection *
3545-gdbus_upstart_ref (void) {
3546- static GDBusConnection * gdbus_upstart = NULL;
3547-
3548- if (gdbus_upstart != NULL) {
3549- return G_DBUS_CONNECTION(g_object_ref(gdbus_upstart));
3550- }
3551-
3552- GError * error = NULL;
3553- gdbus_upstart = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
3554-
3555- if (error != NULL) {
3556- g_warning("Unable to connect to Upstart bus: %s", error->message);
3557- g_error_free(error);
3558- return NULL;
3559- }
3560-
3561- g_object_add_weak_pointer(G_OBJECT(gdbus_upstart), (void **)(&gdbus_upstart));
3562-
3563- return gdbus_upstart;
3564-}
3565-
3566-/* The data we keep for each observer */
3567-typedef struct _observer_t observer_t;
3568-struct _observer_t {
3569- GDBusConnection * conn;
3570- guint sighandle;
3571- UbuntuAppLaunchAppObserver func;
3572- gpointer user_data;
3573-};
3574-
3575-/* The data we keep for each failed observer */
3576-typedef struct _failed_observer_t failed_observer_t;
3577-struct _failed_observer_t {
3578- GDBusConnection * conn;
3579- guint sighandle;
3580- UbuntuAppLaunchAppFailedObserver func;
3581- gpointer user_data;
3582-};
3583-
3584 /* Function to take a work function and have it execute on a given
3585 GMainContext */
3586 static void executeOnContext (const std::shared_ptr<GMainContext>& context, std::function<void()> work)
3587@@ -633,73 +526,6 @@
3588 return observer_delete<UbuntuAppLaunchAppPausedResumedObserver>(observer, user_data, appResumedObservers);
3589 }
3590
3591-typedef void (*per_instance_func_t) (GDBusConnection * con, GVariant * prop_dict, gpointer user_data);
3592-
3593-static void
3594-foreach_job_instance (GDBusConnection * con, const gchar * jobname, per_instance_func_t func, gpointer user_data)
3595-{
3596- const gchar * job_path = get_jobpath(con, jobname);
3597- if (job_path == NULL)
3598- return;
3599-
3600- GError * error = NULL;
3601- GVariant * instance_tuple = g_dbus_connection_call_sync(con,
3602- DBUS_SERVICE_UPSTART,
3603- job_path,
3604- DBUS_INTERFACE_UPSTART_JOB,
3605- "GetAllInstances",
3606- NULL,
3607- G_VARIANT_TYPE("(ao)"),
3608- G_DBUS_CALL_FLAGS_NONE,
3609- -1, /* timeout: default */
3610- NULL, /* cancellable */
3611- &error);
3612-
3613- if (error != NULL) {
3614- g_warning("Unable to get instances of job '%s': %s", jobname, error->message);
3615- g_error_free(error);
3616- return;
3617- }
3618-
3619- GVariant * instance_list = g_variant_get_child_value(instance_tuple, 0);
3620- g_variant_unref(instance_tuple);
3621-
3622- GVariantIter instance_iter;
3623- g_variant_iter_init(&instance_iter, instance_list);
3624- const gchar * instance_path = NULL;
3625-
3626- while (g_variant_iter_loop(&instance_iter, "&o", &instance_path)) {
3627- GVariant * props_tuple = g_dbus_connection_call_sync(con,
3628- DBUS_SERVICE_UPSTART,
3629- instance_path,
3630- "org.freedesktop.DBus.Properties",
3631- "GetAll",
3632- g_variant_new("(s)", DBUS_INTERFACE_UPSTART_INSTANCE),
3633- G_VARIANT_TYPE("(a{sv})"),
3634- G_DBUS_CALL_FLAGS_NONE,
3635- -1, /* timeout: default */
3636- NULL, /* cancellable */
3637- &error);
3638-
3639- if (error != NULL) {
3640- g_warning("Unable to name of instance '%s': %s", instance_path, error->message);
3641- g_error_free(error);
3642- error = NULL;
3643- continue;
3644- }
3645-
3646- GVariant * props_dict = g_variant_get_child_value(props_tuple, 0);
3647-
3648- func(con, props_dict, user_data);
3649-
3650- g_variant_unref(props_dict);
3651- g_variant_unref(props_tuple);
3652-
3653- }
3654-
3655- g_variant_unref(instance_list);
3656-}
3657-
3658 gchar **
3659 ubuntu_app_launch_list_running_apps (void)
3660 {
3661@@ -832,79 +658,6 @@
3662 return g_strdup(std::string(appid).c_str());
3663 }
3664
3665-/* Print an error if we couldn't start it */
3666-static void
3667-start_helper_callback (GObject * obj, GAsyncResult * res, gpointer user_data)
3668-{
3669- GError * error = NULL;
3670- GVariant * result = NULL;
3671-
3672- result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
3673- if (result != NULL)
3674- g_variant_unref(result);
3675-
3676- if (error != NULL) {
3677- g_warning("Unable to start helper: %s", error->message);
3678- g_error_free(error);
3679- }
3680-}
3681-
3682-/* Implements sending the "start" command to Upstart for the
3683- untrusted helper job with the various configuration options
3684- to define the instance. In the end there's only one job with
3685- an array of instances. */
3686-static gboolean
3687-start_helper_core (const gchar * type, const gchar * appid, const gchar * const * uris, const gchar * instance, const gchar * mirsocketpath)
3688-{
3689- GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
3690- g_return_val_if_fail(con != NULL, FALSE);
3691-
3692- const gchar * jobpath = get_jobpath(con, "untrusted-helper");
3693-
3694- /* Build up our environment */
3695- GVariantBuilder builder;
3696- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
3697- g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
3698- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("APP_ID=%s", appid)));
3699- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("HELPER_TYPE=%s", type)));
3700-
3701- if (uris != NULL) {
3702- gchar * urisjoin = app_uris_string(uris);
3703- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("APP_URIS=%s", urisjoin)));
3704- g_free(urisjoin);
3705- }
3706-
3707- if (instance != NULL) {
3708- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("INSTANCE_ID=%s", instance)));
3709- }
3710-
3711- if (mirsocketpath != NULL) {
3712- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("UBUNTU_APP_LAUNCH_DEMANGLE_PATH=%s", mirsocketpath)));
3713- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("UBUNTU_APP_LAUNCH_DEMANGLE_NAME=%s", g_dbus_connection_get_unique_name(con))));
3714- }
3715-
3716- g_variant_builder_close(&builder);
3717- g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
3718-
3719- /* Call the job start function */
3720- g_dbus_connection_call(con,
3721- DBUS_SERVICE_UPSTART,
3722- jobpath,
3723- DBUS_INTERFACE_UPSTART_JOB,
3724- "Start",
3725- g_variant_builder_end(&builder),
3726- NULL,
3727- G_DBUS_CALL_FLAGS_NONE,
3728- -1,
3729- NULL, /* cancellable */
3730- start_helper_callback,
3731- NULL);
3732-
3733- g_object_unref(con);
3734-
3735- return TRUE;
3736-}
3737-
3738 gboolean
3739 ubuntu_app_launch_start_helper (const gchar * type, const gchar * appid, const gchar * const * uris)
3740 {
3741@@ -912,7 +665,27 @@
3742 g_return_val_if_fail(appid != NULL, FALSE);
3743 g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, FALSE);
3744
3745- return start_helper_core(type, appid, uris, NULL, NULL);
3746+ try {
3747+ auto registry = ubuntu::app_launch::Registry::getDefault();
3748+ auto appId = ubuntu::app_launch::AppID::parse(appid);
3749+ auto helper = ubuntu::app_launch::Helper::create(ubuntu::app_launch::Helper::Type::from_raw(type), appId, registry);
3750+
3751+ if (!helper->instances().empty()) {
3752+ throw std::runtime_error{"Instance already exits"};
3753+ }
3754+
3755+ auto uriv = uriVector<ubuntu::app_launch::Helper::URL>(uris);
3756+ auto inst = helper->launch(uriv);
3757+
3758+ if (!inst) {
3759+ throw std::runtime_error{"Empty instance"};
3760+ }
3761+
3762+ return true;
3763+ } catch (std::runtime_error &e) {
3764+ g_warning("Unable to launch helper of type '%s' id '%s': %s", type, appid, e.what());
3765+ return false;
3766+ }
3767 }
3768
3769 gchar *
3770@@ -922,228 +695,23 @@
3771 g_return_val_if_fail(appid != NULL, NULL);
3772 g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, NULL);
3773
3774- gchar * instanceid = g_strdup_printf("%" G_GUINT64_FORMAT, g_get_real_time());
3775-
3776- if (start_helper_core(type, appid, uris, instanceid, NULL)) {
3777- return instanceid;
3778- }
3779-
3780- g_free(instanceid);
3781- return NULL;
3782-}
3783-
3784-/* Transfer from Mir's data structure to ours */
3785-static void
3786-get_mir_session_fd_helper (MirPromptSession * session, size_t count, int const * fdin, void * user_data)
3787-{
3788- auto promise = static_cast<std::promise<int> *>(user_data);
3789-
3790- if (count != 1) {
3791- g_warning("Mir trusted session returned %d FDs instead of one", (int)count);
3792- promise->set_value(0);
3793- return;
3794- }
3795-
3796- promise->set_value(fdin[0]);
3797-}
3798-
3799-/* Setup to get the FD from Mir, blocking */
3800-static int
3801-get_mir_session_fd (MirPromptSession * session)
3802-{
3803- std::promise<int> promise;
3804-
3805- mir_prompt_session_new_fds_for_prompt_providers(session,
3806- 1,
3807- get_mir_session_fd_helper,
3808- &promise);
3809-
3810- return promise.get_future().get();
3811-}
3812-
3813-static GList * open_proxies = NULL;
3814-
3815-static gint
3816-remove_socket_path_find (gconstpointer a, gconstpointer b)
3817-{
3818- GObject * obj = (GObject *)a;
3819- const gchar * path = (const gchar *)b;
3820-
3821- gchar * objpath = (gchar *)g_object_get_qdata(obj, proxy_path_quark());
3822-
3823- return g_strcmp0(objpath, path);
3824-}
3825-
3826-/* Cleans up if we need to early */
3827-static gboolean
3828-remove_socket_path (const gchar * path)
3829-{
3830- GList * thisproxy = g_list_find_custom(open_proxies, path, remove_socket_path_find);
3831- if (thisproxy == NULL)
3832- return FALSE;
3833-
3834- g_debug("Removing Mir Socket Proxy: %s", path);
3835-
3836- GObject * obj = G_OBJECT(thisproxy->data);
3837- open_proxies = g_list_delete_link(open_proxies, thisproxy);
3838-
3839- /* Remove ourselves from DBus if we weren't already */
3840- g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(obj));
3841-
3842- /* If we still have FD, close it */
3843- int mirfd = GPOINTER_TO_INT(g_object_get_qdata(obj, mir_fd_quark()));
3844- if (mirfd != 0) {
3845- close(mirfd);
3846-
3847- /* This is actually an error, we should expect not to find
3848- this here to do anything with it. */
3849- const gchar * props[3] = {
3850- "UbuntuAppLaunchProxyDbusPath",
3851- NULL,
3852- NULL
3853- };
3854- props[1] = path;
3855- whoopsie_report_recoverable_problem("ubuntu-app-launch-mir-fd-proxy", 0, TRUE, props);
3856- }
3857-
3858- g_object_unref(obj);
3859-
3860- return TRUE;
3861-}
3862-
3863-/* Small timeout function that shouldn't, in most cases, ever do anything.
3864- But we need it here to ensure we don't leave things on the bus */
3865-static gboolean
3866-proxy_timeout (gpointer user_data)
3867-{
3868- const gchar * path = (const gchar *)user_data;
3869- remove_socket_path(path);
3870- return G_SOURCE_REMOVE;
3871-}
3872-
3873-/* Removes the whole list of proxies if they are there */
3874-static void
3875-proxy_cleanup_list (void)
3876-{
3877- while (open_proxies) {
3878- GObject * obj = G_OBJECT(open_proxies->data);
3879- gchar * path = (gchar *)g_object_get_qdata(obj, proxy_path_quark());
3880- remove_socket_path(path);
3881- }
3882-}
3883-
3884-static gboolean
3885-proxy_mir_socket (GObject * obj, GDBusMethodInvocation * invocation, gpointer user_data)
3886-{
3887- g_debug("Called to give Mir socket");
3888- int fd = GPOINTER_TO_INT(user_data);
3889-
3890- if (fd == 0) {
3891- g_critical("No FDs to give!");
3892- return FALSE;
3893- }
3894-
3895- /* Index into fds */
3896- GVariant* handle = g_variant_new_handle(0);
3897- GVariant* tuple = g_variant_new_tuple(&handle, 1);
3898-
3899- GError* error = NULL;
3900- GUnixFDList* list = g_unix_fd_list_new();
3901- g_unix_fd_list_append(list, fd, &error);
3902-
3903- if (error == NULL) {
3904- g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, tuple, list);
3905- } else {
3906- g_variant_ref_sink(tuple);
3907- g_variant_unref(tuple);
3908- }
3909-
3910- g_object_unref(list);
3911-
3912- if (error != NULL) {
3913- g_critical("Unable to pass FD %d: %s", fd, error->message);
3914- g_error_free(error);
3915- return FALSE;
3916- }
3917-
3918- g_object_set_qdata(obj, mir_fd_quark(), GINT_TO_POINTER(0));
3919-
3920- return TRUE;
3921-}
3922-
3923-/* Sets up the DBus proxy to send to the demangler */
3924-static gchar *
3925-build_proxy_socket_path (const gchar * appid, int mirfd)
3926-{
3927- static gboolean final_cleanup = FALSE;
3928- if (!final_cleanup) {
3929- std::atexit(proxy_cleanup_list);
3930- final_cleanup = TRUE;
3931- }
3932-
3933- GError * error = NULL;
3934- GDBusConnection * session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
3935- if (error != NULL) {
3936- g_warning("Unable to get session bus: %s", error->message);
3937- g_error_free(error);
3938- return NULL;
3939- }
3940-
3941- /* Export an Object on DBus */
3942- proxySocketDemangler * skel = proxy_socket_demangler_skeleton_new();
3943- g_signal_connect(G_OBJECT(skel), "handle-get-mir-socket", G_CALLBACK(proxy_mir_socket), GINT_TO_POINTER(mirfd));
3944-
3945- gchar * encoded_appid = escape_dbus_string(appid);
3946- gchar * socket_name = NULL;
3947- /* Loop until we fine an object path that isn't taken (probably only once) */
3948- while (socket_name == NULL) {
3949- gchar* tryname = g_strdup_printf("/com/canonical/UbuntuAppLaunch/%s/%X", encoded_appid, g_random_int());
3950- g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(skel),
3951- session,
3952- tryname,
3953- &error);
3954-
3955- if (error == NULL) {
3956- socket_name = tryname;
3957- g_debug("Exporting Mir socket on path: %s", socket_name);
3958- } else {
3959- /* Always print the error, but if the object path is in use let's
3960- not exit the loop. Let's just try again. */
3961- bool exitnow = (error->domain != G_DBUS_ERROR || error->code != G_DBUS_ERROR_OBJECT_PATH_IN_USE);
3962- g_critical("Unable to export trusted session object: %s", error->message);
3963-
3964- g_clear_error(&error);
3965- g_free(tryname);
3966-
3967- if (exitnow) {
3968- break;
3969- }
3970+ try {
3971+ auto registry = ubuntu::app_launch::Registry::getDefault();
3972+ auto appId = ubuntu::app_launch::AppID::parse(appid);
3973+ auto helper = ubuntu::app_launch::Helper::create(ubuntu::app_launch::Helper::Type::from_raw(type), appId, registry);
3974+
3975+ auto uriv = uriVector<ubuntu::app_launch::Helper::URL>(uris);
3976+ auto inst = helper->launch(uriv);
3977+
3978+ if (!inst) {
3979+ throw std::runtime_error{"Empty instance"};
3980 }
3981- }
3982- g_free(encoded_appid);
3983-
3984- /* If we didn't get a socket name, we should just exit. And
3985- make sure to clean up the socket. */
3986- if (socket_name == NULL) {
3987- g_object_unref(skel);
3988- g_object_unref(session);
3989- g_critical("Unable to export object to any name");
3990- return NULL;
3991- }
3992-
3993- g_object_set_qdata_full(G_OBJECT(skel), proxy_path_quark(), g_strdup(socket_name), g_free);
3994- g_object_set_qdata(G_OBJECT(skel), mir_fd_quark(), GINT_TO_POINTER(mirfd));
3995- open_proxies = g_list_prepend(open_proxies, skel);
3996-
3997- g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
3998- 2,
3999- proxy_timeout,
4000- g_strdup(socket_name),
4001- g_free);
4002-
4003- g_object_unref(session);
4004-
4005- return socket_name;
4006+
4007+ return g_strdup(std::dynamic_pointer_cast<ubuntu::app_launch::helper_impls::BaseInstance>(inst)->getInstanceId().c_str());
4008+ } catch (std::runtime_error &e) {
4009+ g_warning("Unable to launch helper of type '%s' id '%s': %s", type, appid, e.what());
4010+ return nullptr;
4011+ }
4012 }
4013
4014 gchar *
4015@@ -1154,89 +722,23 @@
4016 g_return_val_if_fail(appid != NULL, NULL);
4017 g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, NULL);
4018
4019- int mirfd = get_mir_session_fd(session);
4020- if (mirfd == 0)
4021- return NULL;
4022-
4023- gchar * socket_path = build_proxy_socket_path(appid, mirfd);
4024- if (socket_path == NULL) {
4025- close(mirfd);
4026- return NULL;
4027- }
4028-
4029- gchar * instanceid = g_strdup_printf("%" G_GUINT64_FORMAT, g_get_real_time());
4030-
4031- if (start_helper_core(type, appid, uris, instanceid, socket_path)) {
4032- return instanceid;
4033- }
4034-
4035- remove_socket_path(socket_path);
4036- g_free(socket_path);
4037- close(mirfd);
4038- g_free(instanceid);
4039- return NULL;
4040-}
4041-
4042-/* Print an error if we couldn't stop it */
4043-static void
4044-stop_helper_callback (GObject * obj, GAsyncResult * res, gpointer user_data)
4045-{
4046- GError * error = NULL;
4047- GVariant * result = NULL;
4048-
4049- result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
4050- if (result != NULL)
4051- g_variant_unref(result);
4052-
4053- if (error != NULL) {
4054- g_warning("Unable to stop helper: %s", error->message);
4055- g_error_free(error);
4056- }
4057-}
4058-
4059-/* Implements the basis of sending the stop message to Upstart for
4060- an instance of the untrusted-helper job. That also can have an
4061- instance in that we allow for random instance ids to be used for
4062- helpers that are not unique */
4063-static gboolean
4064-stop_helper_core (const gchar * type, const gchar * appid, const gchar * instanceid)
4065-{
4066- GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
4067- g_return_val_if_fail(con != NULL, FALSE);
4068-
4069- const gchar * jobpath = get_jobpath(con, "untrusted-helper");
4070-
4071- /* Build up our environment */
4072- GVariantBuilder builder;
4073- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
4074- g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
4075- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("APP_ID=%s", appid)));
4076- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("HELPER_TYPE=%s", type)));
4077-
4078- if (instanceid != NULL) {
4079- g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf("INSTANCE_ID=%s", instanceid)));
4080- }
4081-
4082- g_variant_builder_close(&builder);
4083- g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
4084-
4085- /* Call the job start function */
4086- g_dbus_connection_call(con,
4087- DBUS_SERVICE_UPSTART,
4088- jobpath,
4089- DBUS_INTERFACE_UPSTART_JOB,
4090- "Stop",
4091- g_variant_builder_end(&builder),
4092- NULL,
4093- G_DBUS_CALL_FLAGS_NONE,
4094- -1,
4095- NULL, /* cancellable */
4096- stop_helper_callback,
4097- NULL);
4098-
4099- g_object_unref(con);
4100-
4101- return TRUE;
4102+ try {
4103+ auto registry = ubuntu::app_launch::Registry::getDefault();
4104+ auto appId = ubuntu::app_launch::AppID::parse(appid);
4105+ auto helper = ubuntu::app_launch::Helper::create(ubuntu::app_launch::Helper::Type::from_raw(type), appId, registry);
4106+
4107+ auto uriv = uriVector<ubuntu::app_launch::Helper::URL>(uris);
4108+ auto inst = helper->launch(session, uriv);
4109+
4110+ if (!inst) {
4111+ throw std::runtime_error{"Empty instance"};
4112+ }
4113+
4114+ return g_strdup(std::dynamic_pointer_cast<ubuntu::app_launch::helper_impls::BaseInstance>(inst)->getInstanceId().c_str());
4115+ } catch (std::runtime_error &e) {
4116+ g_warning("Unable to launch helper of type '%s' id '%s': %s", type, appid, e.what());
4117+ return nullptr;
4118+ }
4119 }
4120
4121 gboolean
4122@@ -1246,7 +748,26 @@
4123 g_return_val_if_fail(appid != NULL, FALSE);
4124 g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, FALSE);
4125
4126- return stop_helper_core(type, appid, NULL);
4127+ try {
4128+ auto registry = ubuntu::app_launch::Registry::getDefault();
4129+ auto appId = ubuntu::app_launch::AppID::parse(appid);
4130+ auto helper = ubuntu::app_launch::Helper::create(ubuntu::app_launch::Helper::Type::from_raw(type), appId, registry);
4131+
4132+ auto insts = helper->instances();
4133+ if (insts.empty()) {
4134+ throw std::runtime_error{"No instances"};
4135+ }
4136+ if (insts.size() > 1u) {
4137+ throw std::runtime_error{"Expecting single instance but has multiple instances"};
4138+ }
4139+
4140+ (*insts.begin())->stop();
4141+
4142+ return TRUE;
4143+ } catch (std::runtime_error &e) {
4144+ g_warning("Unable to stop helper of type '%s' id '%s': %s", type, appid, e.what());
4145+ return FALSE;
4146+ }
4147 }
4148
4149 gboolean
4150@@ -1257,45 +778,23 @@
4151 g_return_val_if_fail(instanceid != NULL, FALSE);
4152 g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, FALSE);
4153
4154- return stop_helper_core(type, appid, instanceid);
4155-}
4156-
4157-
4158-typedef struct {
4159- gchar * type_prefix; /* Type with the colon sperator */
4160- size_t type_len; /* Length in characters of the prefix */
4161- GArray * retappids; /* Array of appids to return */
4162-} helpers_helper_t;
4163-
4164-/* Look at each instance and see if it matches this type, if so
4165- add the appid portion to the array of appids */
4166-static void
4167-list_helpers_helper (GDBusConnection * con, GVariant * props_dict, gpointer user_data)
4168-{
4169- helpers_helper_t * data = (helpers_helper_t *)user_data;
4170-
4171- GVariant * namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
4172- if (namev == NULL) {
4173- return;
4174- }
4175-
4176- const gchar * name = g_variant_get_string(namev, NULL);
4177- if (g_str_has_prefix(name, data->type_prefix)) {
4178- /* Skip the type name */
4179- name += data->type_len;
4180-
4181- /* Skip a possible instance ID */
4182- name = g_strstr_len(name, -1, ":");
4183- name++;
4184-
4185- /* Now copy the app id */
4186- gchar * appid = g_strdup(name);
4187- g_array_append_val(data->retappids, appid);
4188- }
4189-
4190- g_variant_unref(namev);
4191-
4192- return;
4193+ try {
4194+ auto registry = ubuntu::app_launch::Registry::getDefault();
4195+ auto appId = ubuntu::app_launch::AppID::parse(appid);
4196+ auto helper = ubuntu::app_launch::Helper::create(ubuntu::app_launch::Helper::Type::from_raw(type), appId, registry);
4197+
4198+ auto inst = std::dynamic_pointer_cast<ubuntu::app_launch::helper_impls::Base>(helper)->existingInstance(instanceid);
4199+ if (!inst) {
4200+ throw std::runtime_error{"No instances"};
4201+ }
4202+
4203+ inst->stop();
4204+
4205+ return TRUE;
4206+ } catch (std::runtime_error &e) {
4207+ g_warning("Unable to stop helper of type '%s' id '%s' instance '%s': %s", type, appid, instanceid, e.what());
4208+ return FALSE;
4209+ }
4210 }
4211
4212 gchar **
4213@@ -1304,214 +803,99 @@
4214 g_return_val_if_fail(type != NULL, FALSE);
4215 g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, FALSE);
4216
4217- GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
4218- g_return_val_if_fail(con != NULL, FALSE);
4219-
4220- helpers_helper_t helpers_helper_data = {
4221- g_strdup_printf("%s:", type),
4222- strlen(type) + 1, /* 1 for the colon */
4223- g_array_new(TRUE, TRUE, sizeof(gchar *))
4224- };
4225-
4226- foreach_job_instance(con, "untrusted-helper", list_helpers_helper, &helpers_helper_data);
4227-
4228- g_object_unref(con);
4229- g_free(helpers_helper_data.type_prefix);
4230-
4231- return (gchar **)g_array_free(helpers_helper_data.retappids, FALSE);
4232-}
4233-
4234-typedef struct {
4235- gchar * type_prefix; /* Type with the colon sperator */
4236- size_t type_len; /* Length in characters of the prefix */
4237- GArray * retappids; /* Array of appids to return */
4238- gchar * appid_suffix; /* The appid for the end */
4239-} helper_instances_t;
4240-
4241-/* Look at each instance and see if it matches this type and appid.
4242- If so, add the instance ID to the array of instance IDs */
4243-static void
4244-list_helper_instances (GDBusConnection * con, GVariant * props_dict, gpointer user_data)
4245-{
4246- helper_instances_t * data = (helper_instances_t *)user_data;
4247-
4248- GVariant * namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
4249- if (namev == NULL) {
4250- return;
4251- }
4252-
4253- const gchar * name = g_variant_get_string(namev, NULL);
4254- gchar * suffix_loc = NULL;
4255- if (g_str_has_prefix(name, data->type_prefix) &&
4256- (suffix_loc = g_strrstr(name, data->appid_suffix)) != NULL) {
4257- /* Skip the type name */
4258- name += data->type_len;
4259-
4260- /* Now copy the instance id */
4261- gchar * instanceid = g_strndup(name, suffix_loc - name);
4262- g_array_append_val(data->retappids, instanceid);
4263- }
4264-
4265- g_variant_unref(namev);
4266-
4267- return;
4268+ try {
4269+ auto registry = ubuntu::app_launch::Registry::getDefault();
4270+ auto helpers = registry->runningHelpers(ubuntu::app_launch::Helper::Type::from_raw(type));
4271+
4272+ auto array = g_array_new(TRUE, TRUE, sizeof(gchar *));
4273+
4274+ for (const auto &helper : helpers) {
4275+ gchar * appid = g_strdup(std::string(helper->appId()).c_str());
4276+ g_array_append_val(array, appid);
4277+ }
4278+
4279+ return (gchar **)g_array_free(array, FALSE);
4280+ } catch (std::runtime_error &e) {
4281+ g_warning("Unable to get helpers for type '%s': %s", type, e.what());
4282+ return NULL;
4283+ }
4284 }
4285
4286 gchar **
4287 ubuntu_app_launch_list_helper_instances (const gchar * type, const gchar * appid)
4288 {
4289- g_return_val_if_fail(type != NULL, FALSE);
4290- g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, FALSE);
4291-
4292- GDBusConnection * con = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
4293- g_return_val_if_fail(con != NULL, FALSE);
4294-
4295- helper_instances_t helper_instances_data = {
4296- g_strdup_printf("%s:", type),
4297- strlen(type) + 1, /* 1 for the colon */
4298- g_array_new(TRUE, TRUE, sizeof(gchar *)),
4299- g_strdup_printf(":%s", appid)
4300- };
4301-
4302- foreach_job_instance(con, "untrusted-helper", list_helper_instances, &helper_instances_data);
4303-
4304- g_object_unref(con);
4305- g_free(helper_instances_data.type_prefix);
4306- g_free(helper_instances_data.appid_suffix);
4307-
4308- return (gchar **)g_array_free(helper_instances_data.retappids, FALSE);
4309-}
4310-
4311-/* The data we keep for each observer */
4312-typedef struct _helper_observer_t helper_observer_t;
4313-struct _helper_observer_t {
4314- GDBusConnection * conn;
4315- guint sighandle;
4316- gchar * type;
4317- UbuntuAppLaunchHelperObserver func;
4318- gpointer user_data;
4319-};
4320-
4321-/* The lists of helper observers */
4322-static GList * helper_started_obs = NULL;
4323-static GList * helper_stopped_obs = NULL;
4324-
4325-static void
4326-helper_observer_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
4327-{
4328- helper_observer_t * observer = (helper_observer_t *)user_data;
4329-
4330- gchar * env = NULL;
4331- GVariant * envs = g_variant_get_child_value(params, 1);
4332- GVariantIter iter;
4333- g_variant_iter_init(&iter, envs);
4334-
4335- gboolean job_found = FALSE;
4336- gchar * instance = NULL;
4337-
4338- while (g_variant_iter_loop(&iter, "s", &env)) {
4339- if (g_strcmp0(env, "JOB=untrusted-helper") == 0) {
4340- job_found = TRUE;
4341- } else if (g_str_has_prefix(env, "INSTANCE=")) {
4342- instance = g_strdup(env + strlen("INSTANCE="));
4343- }
4344- }
4345-
4346- g_variant_unref(envs);
4347-
4348- if (instance != NULL && !g_str_has_prefix(instance, observer->type)) {
4349- g_free(instance);
4350- instance = NULL;
4351- }
4352-
4353- gchar * appid = NULL;
4354- gchar * instanceid = NULL;
4355- gchar * type = NULL;
4356-
4357- if (instance != NULL) {
4358- gchar ** split = g_strsplit(instance, ":", 3);
4359- type = split[0];
4360- instanceid = split[1];
4361- appid = split[2];
4362- g_free(split);
4363- }
4364- g_free(instance);
4365-
4366- if (instanceid != NULL && instanceid[0] == '\0') {
4367- g_free(instanceid);
4368- instanceid = NULL;
4369- }
4370-
4371- if (job_found && appid != NULL) {
4372- observer->func(appid, instanceid, type, observer->user_data);
4373- }
4374-
4375- g_free(appid);
4376- g_free(instanceid);
4377- g_free(type);
4378-}
4379-
4380-/* Creates the observer structure and registers for the signal with
4381- GDBus so that we can get a callback */
4382-static gboolean
4383-add_helper_generic (UbuntuAppLaunchHelperObserver observer, const gchar * helper_type, gpointer user_data, const gchar * signal, GList ** list)
4384-{
4385- GDBusConnection * conn = gdbus_upstart_ref();
4386-
4387- if (conn == NULL) {
4388- return FALSE;
4389- }
4390-
4391- helper_observer_t * observert = g_new0(helper_observer_t, 1);
4392-
4393- observert->conn = conn;
4394- observert->func = observer;
4395- observert->user_data = user_data;
4396- observert->type = g_strdup_printf("%s:", helper_type);
4397-
4398- *list = g_list_prepend(*list, observert);
4399-
4400- observert->sighandle = g_dbus_connection_signal_subscribe(conn,
4401- NULL, /* sender */
4402- DBUS_INTERFACE_UPSTART, /* interface */
4403- "EventEmitted", /* signal */
4404- DBUS_PATH_UPSTART, /* path */
4405- signal, /* arg0 */
4406- G_DBUS_SIGNAL_FLAGS_NONE,
4407- helper_observer_cb,
4408- observert,
4409- NULL); /* user data destroy */
4410-
4411- return TRUE;
4412-}
4413-
4414-static gboolean
4415-delete_helper_generic (UbuntuAppLaunchHelperObserver observer, const gchar * type, gpointer user_data, GList ** list)
4416-{
4417- helper_observer_t * observert = NULL;
4418- GList * look;
4419-
4420- for (look = *list; look != NULL; look = g_list_next(look)) {
4421- observert = (helper_observer_t *)look->data;
4422-
4423- if (observert->func == observer && observert->user_data == user_data && g_str_has_prefix(observert->type, type)) {
4424- break;
4425- }
4426- }
4427-
4428- if (look == NULL) {
4429- return FALSE;
4430- }
4431-
4432- g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);
4433- g_object_unref(observert->conn);
4434-
4435- g_free(observert->type);
4436- g_free(observert);
4437- *list = g_list_delete_link(*list, look);
4438-
4439- return TRUE;
4440-}
4441+ g_return_val_if_fail(type != NULL, NULL);
4442+ g_return_val_if_fail(g_strstr_len(type, -1, ":") == NULL, NULL);
4443+ g_return_val_if_fail(appid != NULL, NULL);
4444+
4445+ try {
4446+ auto registry = ubuntu::app_launch::Registry::getDefault();
4447+ auto appId = ubuntu::app_launch::AppID::parse(appid);
4448+ auto helper = ubuntu::app_launch::Helper::create(ubuntu::app_launch::Helper::Type::from_raw(type), appId, registry);
4449+
4450+ auto insts = helper->instances();
4451+
4452+ auto array = g_array_new(TRUE, TRUE, sizeof(gchar *));
4453+
4454+ for (const auto &inst : insts) {
4455+ auto internalinst = std::dynamic_pointer_cast<ubuntu::app_launch::helper_impls::BaseInstance>(inst);
4456+ auto cstr = g_strdup(internalinst->getInstanceId().c_str());
4457+ g_array_append_val(array, cstr);
4458+ }
4459+
4460+ return (gchar **)g_array_free(array, FALSE);
4461+ } catch (std::runtime_error &e) {
4462+ g_warning("Unable to get helper instances for '%s' of type '%s': %s", appid, type, e.what());
4463+ return NULL;
4464+ }
4465+}
4466+
4467+/** A handy helper function that is based of a function to get
4468+ a signal and put it into a map. */
4469+template <core::Signal<const std::shared_ptr<ubuntu::app_launch::Helper>&, const std::shared_ptr<ubuntu::app_launch::Helper::Instance>&>& (*getSignal)(ubuntu::app_launch::Helper::Type type, const std::shared_ptr<ubuntu::app_launch::Registry>&)>
4470+static gboolean
4471+helper_add (UbuntuAppLaunchHelperObserver observer, const gchar * helper_type, gpointer user_data, std::map<std::tuple<UbuntuAppLaunchHelperObserver, std::string, gpointer>, core::ScopedConnection> &observers)
4472+{
4473+ auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
4474+ auto type = ubuntu::app_launch::Helper::Type::from_raw(helper_type);
4475+
4476+ observers.emplace(std::make_pair(
4477+ std::make_tuple(observer, type.value(), user_data),
4478+ core::ScopedConnection(
4479+ getSignal(type, ubuntu::app_launch::Registry::getDefault())
4480+ .connect([type, context, observer, user_data](std::shared_ptr<ubuntu::app_launch::Helper> app, std::shared_ptr<ubuntu::app_launch::Helper::Instance> instance) {
4481+ auto internalinst = std::dynamic_pointer_cast<ubuntu::app_launch::helper_impls::BaseInstance>(instance);
4482+
4483+ std::string appid = app->appId();
4484+ std::string instanceid = internalinst->getInstanceId();
4485+
4486+ executeOnContext(context, [appid, instanceid, type, observer, user_data]() {
4487+ observer(appid.c_str(), instanceid.c_str(), type.value().c_str(), user_data);
4488+ });
4489+ })
4490+ )
4491+ ));
4492+
4493+ return TRUE;
4494+}
4495+
4496+static gboolean
4497+helper_delete (UbuntuAppLaunchHelperObserver observer, const gchar * helper_type, gpointer user_data, std::map<std::tuple<UbuntuAppLaunchHelperObserver, std::string, gpointer>, core::ScopedConnection> &observers)
4498+{
4499+ auto type = ubuntu::app_launch::Helper::Type::from_raw(helper_type);
4500+ auto iter = observers.find(std::make_tuple(observer, type.value(), user_data));
4501+
4502+ if (iter == observers.end()) {
4503+ return FALSE;
4504+ }
4505+
4506+ observers.erase(iter);
4507+ return TRUE;
4508+}
4509+
4510+/** Map of all the observers listening for helper started */
4511+static std::map<std::tuple<UbuntuAppLaunchHelperObserver, std::string, gpointer>, core::ScopedConnection> helperStartedObservers;
4512+static std::map<std::tuple<UbuntuAppLaunchHelperObserver, std::string, gpointer>, core::ScopedConnection> helperStoppedObservers;
4513
4514 gboolean
4515 ubuntu_app_launch_observer_add_helper_started (UbuntuAppLaunchHelperObserver observer, const gchar * helper_type, gpointer user_data)
4516@@ -1520,7 +904,7 @@
4517 g_return_val_if_fail(helper_type != NULL, FALSE);
4518 g_return_val_if_fail(g_strstr_len(helper_type, -1, ":") == NULL, FALSE);
4519
4520- return add_helper_generic(observer, helper_type, user_data, "started", &helper_started_obs);
4521+return helper_add<&ubuntu::app_launch::Registry::helperStarted>(observer, helper_type, user_data, helperStartedObservers);
4522 }
4523
4524 gboolean
4525@@ -1530,7 +914,7 @@
4526 g_return_val_if_fail(helper_type != NULL, FALSE);
4527 g_return_val_if_fail(g_strstr_len(helper_type, -1, ":") == NULL, FALSE);
4528
4529- return add_helper_generic(observer, helper_type, user_data, "stopped", &helper_stopped_obs);
4530+ return helper_add<&ubuntu::app_launch::Registry::helperStopped>(observer, helper_type, user_data, helperStoppedObservers);
4531 }
4532
4533 gboolean
4534@@ -1540,7 +924,7 @@
4535 g_return_val_if_fail(helper_type != NULL, FALSE);
4536 g_return_val_if_fail(g_strstr_len(helper_type, -1, ":") == NULL, FALSE);
4537
4538- return delete_helper_generic(observer, helper_type, user_data, &helper_started_obs);
4539+ return helper_delete(observer, helper_type, user_data, helperStartedObservers);
4540 }
4541
4542 gboolean
4543@@ -1550,39 +934,7 @@
4544 g_return_val_if_fail(helper_type != NULL, FALSE);
4545 g_return_val_if_fail(g_strstr_len(helper_type, -1, ":") == NULL, FALSE);
4546
4547- return delete_helper_generic(observer, helper_type, user_data, &helper_stopped_obs);
4548-}
4549-
4550-/* Sets an environment variable in Upstart */
4551-static void
4552-set_var (GDBusConnection * bus, const gchar * job_name, const gchar * instance_name, const gchar * envvar)
4553-{
4554- GVariantBuilder builder; /* Target: (assb) */
4555- g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
4556-
4557- /* Setup the job properties */
4558- g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
4559- g_variant_builder_add_value(&builder, g_variant_new_string(job_name));
4560- if (instance_name != NULL)
4561- g_variant_builder_add_value(&builder, g_variant_new_string(instance_name));
4562- g_variant_builder_close(&builder);
4563-
4564- g_variant_builder_add_value(&builder, g_variant_new_string(envvar));
4565-
4566- /* Do we want to replace? Yes, we do! */
4567- g_variant_builder_add_value(&builder, g_variant_new_boolean(TRUE));
4568-
4569- g_dbus_connection_call(bus,
4570- "com.ubuntu.Upstart",
4571- "/com/ubuntu/Upstart",
4572- "com.ubuntu.Upstart0_6",
4573- "SetEnv",
4574- g_variant_builder_end(&builder),
4575- NULL, /* reply */
4576- G_DBUS_CALL_FLAGS_NONE,
4577- -1, /* timeout */
4578- NULL, /* cancellable */
4579- NULL, NULL); /* callback */
4580+ return helper_delete(observer, helper_type, user_data, helperStoppedObservers);
4581 }
4582
4583 gboolean
4584@@ -1591,70 +943,27 @@
4585 g_return_val_if_fail(execline != NULL, FALSE);
4586 g_return_val_if_fail(execline[0] != '\0', FALSE);
4587
4588- /* Check to see if we can get the job environment */
4589- const gchar * job_name = g_getenv("UPSTART_JOB");
4590- const gchar * instance_name = g_getenv("UPSTART_INSTANCE");
4591- const gchar * demangler = g_getenv("UBUNTU_APP_LAUNCH_DEMANGLE_NAME");
4592- g_return_val_if_fail(job_name != NULL, FALSE);
4593-
4594- GError * error = NULL;
4595- GDBusConnection * bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
4596-
4597- if (error != NULL) {
4598- g_warning("Unable to get session bus: %s", error->message);
4599+ GError * error{nullptr};
4600+ gchar ** splitexec{nullptr};
4601+ if (!g_shell_parse_argv(execline, nullptr, &splitexec, &error) || error != nullptr) {
4602+ g_warning("Unable to parse exec line '%s': %s", execline, error->message);
4603 g_error_free(error);
4604 return FALSE;
4605 }
4606
4607- /* The exec value */
4608- gchar * envstr = NULL;
4609- if (demangler) {
4610- const gchar * demangler_path = g_getenv("UBUNTU_APP_LAUNCH_DEMANGLER");
4611- if (demangler_path == nullptr) {
4612- demangler_path = DEMANGLER_PATH;
4613- }
4614- envstr = g_strdup_printf("APP_EXEC=%s %s", demangler_path, execline);
4615- } else {
4616- envstr = g_strdup_printf("APP_EXEC=%s", execline);
4617- }
4618-
4619- set_var(bus, job_name, instance_name, envstr);
4620- g_free(envstr);
4621-
4622- /* The directory value */
4623- if (directory != NULL) {
4624- gchar * direnv = g_strdup_printf("APP_DIR=%s", directory);
4625- set_var(bus, job_name, instance_name, direnv);
4626- g_free(direnv);
4627- }
4628-
4629- g_object_unref(bus);
4630-
4631- return TRUE;
4632-}
4633-
4634-
4635-/* ensure that all characters are valid in the dbus output string */
4636-static gchar *
4637-escape_dbus_string (const gchar * input)
4638-{
4639- static const gchar *xdigits = "0123456789abcdef";
4640- GString *escaped;
4641- gchar c;
4642-
4643- g_return_val_if_fail (input != NULL, NULL);
4644-
4645- escaped = g_string_new (NULL);
4646- while ((c = *input++)) {
4647- if (g_ascii_isalnum (c)) {
4648- g_string_append_c (escaped, c);
4649- } else {
4650- g_string_append_c (escaped, '_');
4651- g_string_append_c (escaped, xdigits[c >> 4]);
4652- g_string_append_c (escaped, xdigits[c & 0xf]);
4653- }
4654- }
4655-
4656- return g_string_free (escaped, FALSE);
4657+ std::vector<std::string> execvect;
4658+ for (auto i = 0; splitexec[i] != nullptr; i++) {
4659+ execvect.emplace_back(std::string{splitexec[i]});
4660+ }
4661+
4662+ g_strfreev(splitexec);
4663+
4664+ try {
4665+ ubuntu::app_launch::Helper::setExec(execvect);
4666+ return TRUE;
4667+ } catch (std::runtime_error &e) {
4668+ g_warning("Unable to set exec line '%s': %s", execline, e.what());
4669+ return FALSE;
4670+ }
4671 }
4672
4673
4674=== modified file 'tests/CMakeLists.txt'
4675--- tests/CMakeLists.txt 2017-01-19 18:52:33 +0000
4676+++ tests/CMakeLists.txt 2017-02-22 21:41:30 +0000
4677@@ -41,13 +41,12 @@
4678 add_executable (libual-test
4679 libual-test.cc
4680 mir-mock.cpp)
4681-target_link_libraries (libual-test gtest_main ${GTEST_MAIN_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} ubuntu-launcher)
4682+target_link_libraries (libual-test gtest_main ${GTEST_MAIN_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} launcher-static)
4683
4684 add_executable (libual-cpp-test
4685 libual-cpp-test.cc
4686- ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/glib-thread.cpp
4687 mir-mock.cpp)
4688-target_link_libraries (libual-cpp-test gtest_main ${GTEST_MAIN_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} ubuntu-launcher)
4689+target_link_libraries (libual-cpp-test gtest_main ${GTEST_MAIN_LIBRARIES} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} launcher-static)
4690
4691 add_executable (data-spew
4692 data-spew.c)
4693@@ -115,45 +114,6 @@
4694
4695 file(COPY data DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
4696
4697-# Failure Test
4698-
4699-add_definitions ( -DAPP_FAILED_TOOL="${CMAKE_BINARY_DIR}/application-failed" )
4700-
4701-add_executable (failure-test
4702- failure-test.cc)
4703-target_link_libraries (failure-test gtest_main ${GTEST_MAIN_LIBRARIES} ubuntu-launcher)
4704-add_test (failure-test failure-test)
4705-
4706-# ZG Test
4707-
4708-add_definitions ( -DZG_EVENT_TOOL="${CMAKE_BINARY_DIR}/zg-report-app" )
4709-
4710-add_executable (zg-test
4711- zg-test.cc)
4712-target_link_libraries (zg-test gtest_main ${GTEST_MAIN_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES})
4713-add_test (zg-test zg-test)
4714-
4715-# Exec Line Exec Test
4716-
4717-configure_file("exec-test.sh.in" "${CMAKE_CURRENT_BINARY_DIR}/exec-test.sh" @ONLY)
4718-add_test (exec-test "${CMAKE_CURRENT_BINARY_DIR}/exec-test.sh")
4719-
4720-# Exec Utils
4721-
4722-add_executable (exec-util-test
4723- exec-util-test.cc)
4724-target_link_libraries (exec-util-test gtest_main ubuntu-launcher ${GTEST_MAIN_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES})
4725-add_test (exec-util-test exec-util-test)
4726-
4727-# CGroup Reap Test
4728-
4729-add_definitions ( -DCG_REAP_TOOL="${CMAKE_BINARY_DIR}/cgroup-reap-all" )
4730-
4731-add_executable (cgroup-reap-test
4732- cgroup-reap-test.cc)
4733-target_link_libraries (cgroup-reap-test gtest_main ${GTEST_MAIN_LIBRARIES} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES})
4734-add_test (cgroup-reap-test cgroup-reap-test)
4735-
4736 # Desktop Hook Test
4737
4738 configure_file ("click-desktop-hook-db/test.conf.in" "${CMAKE_CURRENT_BINARY_DIR}/click-desktop-hook-db/test.conf" @ONLY)
4739@@ -174,7 +134,6 @@
4740
4741 add_custom_target(format-tests
4742 COMMAND clang-format -i -style=file
4743- failure-test.cc
4744 application-info-desktop.cpp
4745 libual-cpp-test.cc
4746 list-apps.cpp
4747@@ -187,4 +146,5 @@
4748 spew-master.h
4749 systemd-mock.h
4750 zg-test.cc
4751+ zg-mock.h
4752 )
4753
4754=== removed file 'tests/cgroup-reap-test.cc'
4755--- tests/cgroup-reap-test.cc 2017-01-11 23:22:52 +0000
4756+++ tests/cgroup-reap-test.cc 1970-01-01 00:00:00 +0000
4757@@ -1,145 +0,0 @@
4758-/*
4759- * Copyright 2014 Canonical Ltd.
4760- *
4761- * This program is free software: you can redistribute it and/or modify it
4762- * under the terms of the GNU General Public License version 3, as published
4763- * by the Free Software Foundation.
4764- *
4765- * This program is distributed in the hope that it will be useful, but
4766- * WITHOUT ANY WARRANTY; without even the implied warranties of
4767- * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
4768- * PURPOSE. See the GNU General Public License for more details.
4769- *
4770- * You should have received a copy of the GNU General Public License along
4771- * with this program. If not, see <http://www.gnu.org/licenses/>.
4772- *
4773- * Authors:
4774- * Ted Gould <ted.gould@canonical.com>
4775- */
4776-
4777-#include <gtest/gtest.h>
4778-#include <gio/gio.h>
4779-#include <libdbustest/dbus-test.h>
4780-
4781-class CGroupReap : public ::testing::Test
4782-{
4783- protected:
4784- DbusTestService * service = NULL;
4785- DbusTestDbusMock * cgmock = NULL;
4786- GDBusConnection * bus = NULL;
4787- GPid sleeppid = 0;
4788-
4789- virtual void SetUp() {
4790- const gchar * argv[] = { "sleep", "30", NULL };
4791- g_spawn_async(NULL,
4792- (gchar **)argv,
4793- NULL, /* env */
4794- G_SPAWN_SEARCH_PATH,
4795- NULL, NULL, /* child setup */
4796- &sleeppid,
4797- NULL); /* error */
4798- ASSERT_NE(0, sleeppid);
4799-
4800- service = dbus_test_service_new(NULL);
4801-
4802- /* Create the cgroup manager mock */
4803- cgmock = dbus_test_dbus_mock_new("org.test.cgmock");
4804- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_NAME", "org.test.cgmock", TRUE);
4805-
4806- DbusTestDbusMockObject * cgobject = dbus_test_dbus_mock_get_object(cgmock, "/org/linuxcontainers/cgmanager", "org.linuxcontainers.cgmanager0_0", NULL);
4807- /* This Python code executes in dbusmock and checks to see if the sleeping
4808- process is running. If it is, it returns its PID in the list of PIDs, if
4809- not it doesn't return any PIDs. */
4810- gchar * pythoncode = g_strdup_printf(
4811- "if os.spawnlp(os.P_WAIT, 'ps', 'ps', '%d') == 0 :\n"
4812- " ret = [ %d ]\n"
4813- "else:\n"
4814- " ret = [ ]",
4815- sleeppid, sleeppid);
4816- dbus_test_dbus_mock_object_add_method(cgmock, cgobject,
4817- "GetTasksRecursive",
4818- G_VARIANT_TYPE("(ss)"),
4819- G_VARIANT_TYPE("ai"),
4820- pythoncode,
4821- NULL);
4822- g_free(pythoncode);
4823-
4824- /* Put it together */
4825- dbus_test_service_add_task(service, DBUS_TEST_TASK(cgmock));
4826- dbus_test_service_start_tasks(service);
4827-
4828- bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
4829- g_dbus_connection_set_exit_on_close(bus, FALSE);
4830- g_object_add_weak_pointer(G_OBJECT(bus), (gpointer *)&bus);
4831-
4832- /* Make sure we pretend the CG manager is just on our bus */
4833- g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS", "YES", TRUE);
4834- }
4835-
4836- virtual void TearDown() {
4837- g_clear_object(&cgmock);
4838- g_clear_object(&service);
4839-
4840- g_object_unref(bus);
4841-
4842- unsigned int cleartry = 0;
4843- while (bus != NULL && cleartry < 100) {
4844- pause(100);
4845- cleartry++;
4846- }
4847- ASSERT_EQ(bus, nullptr);
4848-
4849- g_debug("Killing the sleeper: %d", sleeppid);
4850- kill(sleeppid, SIGKILL);
4851- }
4852-
4853- static gboolean pause_helper (gpointer pmainloop) {
4854- g_main_loop_quit(static_cast<GMainLoop *>(pmainloop));
4855- return G_SOURCE_REMOVE;
4856- }
4857-
4858- void pause (guint time) {
4859- if (time > 0) {
4860- GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
4861- g_timeout_add(time, pause_helper, mainloop);
4862-
4863- g_main_loop_run(mainloop);
4864-
4865- g_main_loop_unref(mainloop);
4866- }
4867-
4868- while (g_main_pending()) {
4869- g_main_iteration(TRUE);
4870- }
4871- }
4872-
4873- bool sleepRunning (void) {
4874- gint status = 1;
4875- gchar * cmdline = g_strdup_printf("ps %d", sleeppid);
4876-
4877- g_spawn_command_line_sync(cmdline, NULL, NULL, &status, NULL);
4878- g_free(cmdline);
4879-
4880- return status == 0;
4881- }
4882-};
4883-
4884-TEST_F(CGroupReap, KillSleep)
4885-{
4886- g_setenv("UPSTART_JOB", "foo", TRUE);
4887- g_setenv("UPSTART_INSTANCE", "bar", TRUE);
4888-
4889- ASSERT_TRUE(g_spawn_command_line_sync(CG_REAP_TOOL, NULL, NULL, NULL, NULL));
4890- EXPECT_FALSE(sleepRunning());
4891-
4892- DbusTestDbusMockObject * cgobject = dbus_test_dbus_mock_get_object(cgmock, "/org/linuxcontainers/cgmanager", "org.linuxcontainers.cgmanager0_0", NULL);
4893- const DbusTestDbusMockCall * calls = NULL;
4894- guint len = 0;
4895-
4896- calls = dbus_test_dbus_mock_object_get_method_calls(cgmock, cgobject, "GetTasksRecursive", &len, NULL);
4897- EXPECT_EQ(2u, len);
4898- EXPECT_STREQ("GetTasksRecursive", calls->name);
4899- EXPECT_TRUE(g_variant_equal(calls->params, g_variant_new("(ss)", "freezer", "")));
4900- ASSERT_TRUE(dbus_test_dbus_mock_object_clear_method_calls(cgmock, cgobject, NULL));
4901-}
4902-
4903
4904=== removed file 'tests/exec-test-archcolon.sh'
4905--- tests/exec-test-archcolon.sh 2014-04-30 21:43:28 +0000
4906+++ tests/exec-test-archcolon.sh 1970-01-01 00:00:00 +0000
4907@@ -1,18 +0,0 @@
4908-#!/bin/bash -e
4909-
4910-if [ "$PATH" != "$APP_DIR:/path" ] ; then
4911- echo "Bad PATH: $PATH"
4912- exit 1
4913-fi
4914-
4915-if [ "$LD_LIBRARY_PATH" != "$APP_DIR/lib:/lib" ] ; then
4916- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
4917- exit 1
4918-fi
4919-
4920-if [ "$QML2_IMPORT_PATH" != "/bar/qml/import" ] ; then
4921- echo "Bad QML import path: $QML2_IMPORT_PATH"
4922- exit 1
4923-fi
4924-
4925-exit 0
4926
4927=== removed file 'tests/exec-test-colon.sh'
4928--- tests/exec-test-colon.sh 2014-04-30 21:43:28 +0000
4929+++ tests/exec-test-colon.sh 1970-01-01 00:00:00 +0000
4930@@ -1,18 +0,0 @@
4931-#!/bin/bash -e
4932-
4933-if [ "$PATH" != "/path" ] ; then
4934- echo "Bad PATH: $PATH"
4935- exit 1
4936-fi
4937-
4938-if [ "$LD_LIBRARY_PATH" != "/lib" ] ; then
4939- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
4940- exit 1
4941-fi
4942-
4943-if [ "$QML2_IMPORT_PATH" != "/bar/qml/import" ] ; then
4944- echo "Bad QML import path: $QML2_IMPORT_PATH"
4945- exit 1
4946-fi
4947-
4948-exit 0
4949
4950=== removed file 'tests/exec-test-full.sh'
4951--- tests/exec-test-full.sh 2014-04-30 21:43:28 +0000
4952+++ tests/exec-test-full.sh 1970-01-01 00:00:00 +0000
4953@@ -1,18 +0,0 @@
4954-#!/bin/bash -e
4955-
4956-if [ "$PATH" != "$APP_DIR/lib/64bit-amazing/bin:$APP_DIR:/path" ] ; then
4957- echo "Bad PATH: $PATH"
4958- exit 1
4959-fi
4960-
4961-if [ "$LD_LIBRARY_PATH" != "$APP_DIR/lib/64bit-amazing:$APP_DIR/lib:/lib" ] ; then
4962- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
4963- exit 1
4964-fi
4965-
4966-if [ "$QML2_IMPORT_PATH" != "/bar/qml/import:$APP_DIR/lib/64bit-amazing" ] ; then
4967- echo "Bad QML import path: $QML2_IMPORT_PATH"
4968- exit 1
4969-fi
4970-
4971-exit 0
4972
4973=== removed file 'tests/exec-test-noarch.sh'
4974--- tests/exec-test-noarch.sh 2014-04-30 21:43:28 +0000
4975+++ tests/exec-test-noarch.sh 1970-01-01 00:00:00 +0000
4976@@ -1,18 +0,0 @@
4977-#!/bin/bash -e
4978-
4979-if [ "$PATH" != "$APP_DIR:/path" ] ; then
4980- echo "Bad PATH: $PATH"
4981- exit 1
4982-fi
4983-
4984-if [ "$LD_LIBRARY_PATH" != "$APP_DIR/lib:/lib" ] ; then
4985- echo "Bad LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
4986- exit 1
4987-fi
4988-
4989-if [ "$QML2_IMPORT_PATH" != "/bar/qml/import" ] ; then
4990- echo "Bad QML import path: $QML2_IMPORT_PATH"
4991- exit 1
4992-fi
4993-
4994-exit 0
4995
4996=== removed file 'tests/exec-test-noinit.sh'
4997--- tests/exec-test-noinit.sh 2014-04-30 21:43:28 +0000
4998+++ tests/exec-test-noinit.sh 1970-01-01 00:00:00 +0000
4999@@ -1,18 +0,0 @@
5000-#!/bin/bash -e
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches