=== modified file 'libubuntu-app-launch/CMakeLists.txt'
--- libubuntu-app-launch/CMakeLists.txt	2017-03-20 10:13:50 +0000
+++ libubuntu-app-launch/CMakeLists.txt	2017-04-05 12:08:51 +0000
@@ -80,7 +80,7 @@
 
 set(LAUNCHER_SOURCES
 ubuntu-app-launch.cpp
-second-exec-core.c
+second-exec-core.cpp
 ubuntu-app-launch-trace.c
 utils.c
 utils-shared.c

=== modified file 'libubuntu-app-launch/jobs-base.cpp'
--- libubuntu-app-launch/jobs-base.cpp	2017-04-05 12:08:51 +0000
+++ libubuntu-app-launch/jobs-base.cpp	2017-04-05 12:08:51 +0000
@@ -1053,29 +1053,6 @@
     }
 }
 
-/** Reformat a C++ vector of URLs into a C GStrv of strings
-
-    \param urls Vector of URLs to make into C strings
-*/
-GCharVUPtr Base::urlsToStrv(const std::vector<Application::URL>& urls)
-{
-    if (urls.empty())
-    {
-        return GCharVUPtr(nullptr, &g_strfreev);
-    }
-
-    auto array = g_array_new(TRUE, FALSE, sizeof(gchar*));
-
-    for (auto url : urls)
-    {
-        auto str = g_strdup(url.value().c_str());
-        g_debug("Converting URL: %s", str);
-        g_array_append_val(array, str);
-    }
-
-    return unique_gcharv((gchar**)g_array_free(array, FALSE));
-}
-
 }  // namespace instance
 
 }  // namespace jobs

=== modified file 'libubuntu-app-launch/jobs-base.h'
--- libubuntu-app-launch/jobs-base.h	2017-04-05 12:08:51 +0000
+++ libubuntu-app-launch/jobs-base.h	2017-04-05 12:08:51 +0000
@@ -91,7 +91,6 @@
     static void oomValueToPid(pid_t pid, const oom::Score oomvalue);
     static void oomValueToPidHelper(pid_t pid, const oom::Score oomvalue);
     static std::string pidToOomPath(pid_t pid);
-    static GCharVUPtr urlsToStrv(const std::vector<Application::URL>& urls);
 };
 
 }  // namespace instance

=== modified file 'libubuntu-app-launch/jobs-systemd.cpp'
--- libubuntu-app-launch/jobs-systemd.cpp	2017-04-05 12:08:51 +0000
+++ libubuntu-app-launch/jobs-systemd.cpp	2017-04-05 12:08:51 +0000
@@ -513,13 +513,12 @@
             g_debug("Remote error: %s", remote_error);
             if (g_strcmp0(remote_error, "org.freedesktop.systemd1.UnitExists") == 0)
             {
-                auto urls = instance::SystemD::urlsToStrv(data->ptr->urls_);
-                second_exec(data->bus.get(),                                     /* DBus */
-                            data->ptr->registry_->thread.getCancellable().get(), /* cancellable */
-                            data->ptr->primaryPid(),                             /* primary pid */
-                            std::string(data->ptr->appId_).c_str(),              /* appid */
-                            data->ptr->instance_.c_str(),                        /* instance */
-                            urls.get());                                         /* urls */
+                second_exec(data->bus,                                     /* DBus */
+                            data->ptr->registry_->thread.getCancellable(), /* cancellable */
+                            data->ptr->primaryPid(),                       /* primary pid */
+                            std::string(data->ptr->appId_),                /* appid */
+                            data->ptr->instance_,                          /* instance */
+                            data->ptr->urls_);                             /* urls */
             }
 
             g_free(remote_error);

=== renamed file 'libubuntu-app-launch/second-exec-core.c' => 'libubuntu-app-launch/second-exec-core.cpp'
--- libubuntu-app-launch/second-exec-core.c	2017-03-14 22:41:03 +0000
+++ libubuntu-app-launch/second-exec-core.cpp	2017-04-05 12:08:51 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Canonical Ltd.
+ * Copyright 2013-2017 Canonical Ltd.
  *
  * This program is free software: you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 3, as published
@@ -15,138 +15,230 @@
  *
  * Authors:
  *     Ted Gould <ted.gould@canonical.com>
+ *     Pete Woods <pete.woods@canonical.com>
  */
 
 #include <gio/gio.h>
 #include "libubuntu-app-launch/ubuntu-app-launch.h"
-#include "utils.h"
 #include "second-exec-core.h"
+#include "signal-unsubscriber.h"
 #include "ubuntu-app-launch-trace.h"
 #include "ual-tracepoint.h"
 
-typedef struct {
-	GDBusConnection * bus;
-	gchar * appid;
-	gchar * instanceid;
-	gchar ** input_uris;
-	GPid app_pid;
-	guint connections_open;
-	GVariant * app_data;
-	gchar * dbus_path;
-	guint64 unity_starttime;
-	GSource * timer;
-	guint signal;
-} second_exec_t;
-
-static void second_exec_complete (second_exec_t * data);
-
-static GSource *
-thread_default_timeout (guint interval, GSourceFunc func, gpointer data)
-{
-	GSource * src = g_timeout_source_new(interval);
-	GMainContext * context = g_main_context_get_thread_default();
-
-	g_source_set_callback(src, func, data, NULL);
-
-	g_source_attach(src, context);
+#include <unity/util/GlibMemory.h>
+
+#include <iomanip>
+#include <sstream>
+#include <unordered_map>
+
+using namespace std;
+using namespace unity::util;
+
+namespace ubuntu
+{
+namespace app_launch
+{
+namespace
+{
+
+struct GSourceClear
+{
+	void operator()(GSource* source)
+	{
+		if (source != nullptr)
+		{
+			g_source_destroy(source);
+			g_source_unref(source);
+		}
+	}
+};
+
+
+class second_exec_t: public enable_shared_from_this<second_exec_t>
+{
+public:
+	second_exec_t(shared_ptr<GDBusConnection> bus, const string& appid, const string& instanceid, const vector<Application::URL>& input_uris, GPid app_pid);
+
+	~second_exec_t();
+
+	void
+	init ();
+
+private:
+	class get_pid_t
+	{
+	public:
+		get_pid_t(const string& name, shared_ptr<GDBusConnection> bus, shared_ptr<second_exec_t> data);
+
+	private:
+		static void
+		get_pid_cb (GObject * object, GAsyncResult * res, gpointer user_data)
+		{
+			((get_pid_t *)user_data)->get_pid(object, res);
+		}
+
+		void
+		get_pid (GObject * object, GAsyncResult * res);
+
+		string name;
+
+		shared_ptr<second_exec_t> data;
+	};
+
+	/* Unity didn't respond in time, continue on */
+	static gboolean
+	timer_cb (gpointer user_data);
+
+	static void
+	send_open_cb (GObject * object, GAsyncResult * res, gpointer user_data)
+	{
+		((second_exec_t*) user_data)->send_open(object, res);
+	}
+
+	void
+	app_id_to_dbus_path ();
+
+	void
+	send_open (GObject * object, GAsyncResult * res);
+
+	void
+	contact_app (GDBusConnection * bus, const string& dbus_name);
+
+	void
+	find_appid_pid ();
+
+	void
+	connection_count_dec ();
+
+	static void
+	unity_resume_cb (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
+	{
+		((second_exec_t*) user_data)->unity_resume(connection, sender, path, interface, signal, params);
+	}
+
+	void
+	unity_resume(GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params);
+
+	void
+	parse_uris ();
+
+	static GSourceUPtr
+	thread_default_timeout (guint interval, GSourceFunc func, gpointer data);
+
+	void finish();
+
+	static unordered_map<second_exec_t*, shared_ptr<second_exec_t>> SECOND_EXEC_INSTANCES_;
+
+	shared_ptr<GDBusConnection> bus_;
+	string appid_;
+	string instanceid_;
+	vector<Application::URL> input_uris_;
+	GPid app_pid_;
+	guint connections_open {0};
+	GVariantSPtr app_data{nullptr, GVariantDeleter()};
+	string dbus_path;
+	guint64 unity_starttime {0};
+	GSourceSPtr timer{nullptr, GSourceClear()};
+	ManagedDBusSignalConnection signal {DBusSignalUnsubscriber()};
+};
+
+unordered_map<second_exec_t*, shared_ptr<second_exec_t>> second_exec_t::SECOND_EXEC_INSTANCES_;
+
+GSourceUPtr
+second_exec_t::thread_default_timeout (guint interval, GSourceFunc func, gpointer data)
+{
+	auto src = unique_glib(g_timeout_source_new(interval));
+	auto context = unique_glib(g_main_context_get_thread_default());
+
+	g_source_set_callback(src.get(), func, data, nullptr);
+
+	g_source_attach(src.get(), context.get());
 
 	return src;
 }
 
 /* Unity didn't respond in time, continue on */
-static gboolean
-timer_cb (gpointer user_data)
+gboolean
+second_exec_t::timer_cb (gpointer user_data)
 {
-	ual_tracepoint(second_exec_resume_timeout, ((second_exec_t *)user_data)->appid);
+	auto data = (second_exec_t *)user_data;
+	ual_tracepoint(second_exec_resume_timeout, data->appid_.c_str());
 	g_warning("Unity didn't respond in 500ms to resume the app");
 
-	second_exec_complete(user_data);
+	data->finish();
 	return G_SOURCE_REMOVE;
 }
 
 /* Lower the connection count and process if it gets to zero */
-static void
-connection_count_dec (second_exec_t * data)
+void
+second_exec_t::connection_count_dec ()
 {
-	ual_tracepoint(second_exec_connection_complete, data->appid);
-	data->connections_open--;
-	if (data->connections_open == 0) {
+	ual_tracepoint(second_exec_connection_complete, appid_.c_str());
+	connections_open--;
+	if (connections_open == 0) {
 		g_debug("Finished finding connections");
 		/* Check time here, either we've already heard from
 		   Unity and we should send the data to the app (quit) or
 		   we should wait some more */
-		guint64 timespent = g_get_monotonic_time() - data->unity_starttime;
+		guint64 timespent = g_get_monotonic_time() - unity_starttime;
 		if (timespent > 500 /* ms */ * 1000 /* ms to us */) {
-			second_exec_complete(data);
+			finish();
+			return;
 		} else {
 			g_debug("Timer Set");
-			data->timer = thread_default_timeout(500 - (timespent / 1000), timer_cb, data);
+			timer = thread_default_timeout(500 - (timespent / 1000), timer_cb, this);
 		}
 	}
-	return;
 }
 
 /* Called when Unity is done unfreezing the application, if we're
    done determining the PID, we can send signals */
-static void
-unity_resume_cb (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
+void
+second_exec_t::unity_resume(GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params)
 {
-	second_exec_t * data = (second_exec_t *)user_data;
 	g_debug("Unity Completed Resume");
-	ual_tracepoint(second_exec_resume_complete, data->appid);
-
-	if (data->timer != NULL) {
-		g_source_destroy(data->timer);
-		g_source_unref(data->timer);
-		data->timer = NULL;
-	}
-
-	if (data->connections_open == 0) {
-		second_exec_complete(data);
+	ual_tracepoint(second_exec_resume_complete, appid_.c_str());
+
+	timer.reset();
+
+	if (connections_open == 0) {
+		finish();
 	} else {
 		/* Make it look like we started *forever* ago */
-		data->unity_starttime = 0;
+		unity_starttime = 0;
 	}
-
-	return;
 }
 
 /* Turn the input string into something we can send to apps */
-static void
-parse_uris (second_exec_t * data)
+void
+second_exec_t::parse_uris ()
 {
-	if (data->app_data != NULL) {
+	if (app_data) {
 		/* Already done */
 		return;
 	}
 
-	GVariant * uris = NULL;
+	GVariant * uris = nullptr;
 
-	if (data->input_uris == NULL) {
-		uris = g_variant_new_array(G_VARIANT_TYPE_STRING, NULL, 0);
+	if (input_uris_.empty()) {
+		uris = g_variant_new_array(G_VARIANT_TYPE_STRING, nullptr, 0);
 	} else {
 		GVariantBuilder builder;
 		g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
 
-		int i;
-		for (i = 0; data->input_uris[i] != NULL; i++) {
-			g_variant_builder_add_value(&builder, g_variant_new_string(data->input_uris[i]));
+		for (const auto& uri: input_uris_) {
+			g_variant_builder_add_value(&builder, g_variant_new_string(uri.value().c_str()));
 		}
 
 		uris = g_variant_builder_end(&builder);
 	}
 
-	GVariant * platform = g_variant_new_array(G_VARIANT_TYPE("{sv}"), NULL, 0);
-
 	GVariantBuilder tuple;
 	g_variant_builder_init(&tuple, G_VARIANT_TYPE_TUPLE);
 	g_variant_builder_add_value(&tuple, uris);
-	g_variant_builder_add_value(&tuple, platform);
-
-	data->app_data = g_variant_builder_end(&tuple);
-	g_variant_ref_sink(data->app_data);
-
-	return;
+	g_variant_builder_add_value(&tuple, g_variant_new_array(G_VARIANT_TYPE("{sv}"), nullptr, 0));
+
+	app_data = unique_glib(g_variant_ref_sink(g_variant_builder_end(&tuple)));
 }
 
 /* Finds us our dbus path to use.  Basically this is the name
@@ -155,322 +247,303 @@
 
    http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus   
 */
-static void
-app_id_to_dbus_path (second_exec_t * data)
+void
+second_exec_t::app_id_to_dbus_path ()
 {
-	if (data->dbus_path != NULL) {
+	if (!dbus_path.empty()) {
 		return;
 	}
 
-	GString * str = g_string_sized_new(strlen(data->appid) + 2); /* base case, we just need a / and a null */
-	g_string_append_c(str, '/');
-
-	int i;
-	for (i = 0; data->appid[i] != '\0'; i++) {
-		if ((data->appid[i] >= 'a' && data->appid[i] <= 'z') ||
-			(data->appid[i] >= 'A' && data->appid[i] <= 'Z') ||
-			(data->appid[i] >= '0' && data->appid[i] <= '9' && i != 0)) {
-			g_string_append_c(str, data->appid[i]);
-			continue;
-		}
-
-		g_string_append_printf(str, "_%2x", data->appid[i]);
+	stringstream str;
+	auto defaultFlags = str.flags();
+	str << "/";
+
+	bool first = true;
+	for (const auto c: appid_) {
+		if ((c >= 'a' && c <= 'z') ||
+			(c >= 'A' && c <= 'Z') ||
+			(c >= '0' && c <= '9' && !first))
+		{
+			str << c;
+		}
+		else
+		{
+			str << "_" << setfill('0') << setw(2) << hex << c;
+			str.flags(defaultFlags);
+		}
+		first = false;
 	}
 
-	data->dbus_path = g_string_free(str, FALSE);
-	g_debug("DBus Path: %s", data->dbus_path);
-
-	return;
+	dbus_path = str.str();
+	g_debug("DBus Path: %s", dbus_path.c_str());
 }
 
 /* Finish the send and decrement the counter */
-static void
-send_open_cb (GObject * object, GAsyncResult * res, gpointer user_data)
+void
+second_exec_t::send_open (GObject * object, GAsyncResult * res)
 {
-	GError * error = NULL;
+	GError * error = nullptr;
 
-	ual_tracepoint(second_exec_app_contacted, ((second_exec_t *)user_data)->appid);
+	ual_tracepoint(second_exec_app_contacted, appid_.c_str());
 
 	g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
 
-	if (error != NULL) {
-		ual_tracepoint(second_exec_app_error, ((second_exec_t *)user_data)->appid);
+	if (error != nullptr) {
+		ual_tracepoint(second_exec_app_error, appid_.c_str());
 		/* Mostly just to free the error, but printing for debugging */
 		g_debug("Unable to send Open: %s", error->message);
-		g_error_free(error);
+		g_clear_error(&error);
 	}
 
-	connection_count_dec(user_data);
-	return;
+	connection_count_dec();
 }
 
 /* Sends the Open message to the connection with the URIs we were given */
-static void
-contact_app (GDBusConnection * bus, const gchar * dbus_name, second_exec_t * data)
+void
+second_exec_t::contact_app (GDBusConnection * bus, const string& dbus_name)
 {
-	ual_tracepoint(second_exec_contact_app, data->appid, dbus_name);
+	ual_tracepoint(second_exec_contact_app, appid_.c_str(), dbus_name.c_str());
 
-	parse_uris(data);
-	app_id_to_dbus_path(data);
+	parse_uris();
+	app_id_to_dbus_path();
 
 	/* Using the FD.o Application interface */
 	g_dbus_connection_call(bus,
-		dbus_name,
-		data->dbus_path,
+		dbus_name.c_str(),
+		dbus_path.c_str(),
 		"org.freedesktop.Application",
 		"Open",
-		data->app_data,
-		NULL,
-		G_DBUS_CALL_FLAGS_NONE,
-		-1,
-		NULL,
-		send_open_cb, data);
-
-	g_debug("Sending Open request to: %s", dbus_name);
-
-	return;
-}
-
-typedef struct {
-	gchar * name;
-	second_exec_t * data;
-} get_pid_t;
+		app_data.get(),
+		NULL,
+		G_DBUS_CALL_FLAGS_NONE,
+		-1,
+		NULL,
+		second_exec_t::send_open_cb, this);
+
+	g_debug("Sending Open request to: %s", dbus_name.c_str());
+}
+
+second_exec_t::get_pid_t::get_pid_t(const string& _name, shared_ptr<GDBusConnection> bus, shared_ptr<second_exec_t> _data) :
+		name(_name), data(_data)
+{
+	/* Get the PIDs */
+	g_dbus_connection_call(bus.get(),
+		"org.freedesktop.DBus",
+		"/",
+		"org.freedesktop.DBus",
+		"GetConnectionUnixProcessID",
+		g_variant_new("(s)", name.c_str()),
+		G_VARIANT_TYPE("(u)"),
+		G_DBUS_CALL_FLAGS_NONE,
+		-1,
+		nullptr,
+		get_pid_t::get_pid_cb, this);
+}
 
 /* Gets the PID for a connection, and if it matches the one we're looking
    for then it tries to send a message to that connection */
-static void
-get_pid_cb (GObject * object, GAsyncResult * res, gpointer user_data)
+void
+second_exec_t::get_pid_t::get_pid (GObject * object, GAsyncResult * res)
 {
-	get_pid_t * data = (get_pid_t *)user_data;
-	GError * error = NULL;
-	GVariant * vpid = NULL;
-
-	ual_tracepoint(second_exec_got_pid, data->data->appid, data->name);
-
-	vpid = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
-
-	if (error != NULL) {
-		g_warning("Unable to query PID for dbus name '%s': %s", data->name, error->message);
-		g_error_free(error);
+	GError * error = nullptr;
+
+	ual_tracepoint(second_exec_got_pid, data->appid_.c_str(), name.c_str());
+
+	auto vpid = unique_glib(g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error));
+
+	if (error != nullptr) {
+		g_warning("Unable to query PID for dbus name '%s': %s", name.c_str(), error->message);
+		g_clear_error(&error);
 
 		/* Lowering the connection count, this one is terminal, even if in error */
-		connection_count_dec(data->data);
-
-		g_free(data->name);
-		g_free(data);
-
-		return;
-	}
-
-	guint pid = 0;
-	g_variant_get(vpid, "(u)", &pid);
-	g_variant_unref(vpid);
-
-	if (pid == data->data->app_pid) {
-		/* Trying to send a message to the connection */
-		contact_app(G_DBUS_CONNECTION(object), data->name, data->data);
+		data->connection_count_dec();
 	} else {
-		/* See if we can quit now */
-		connection_count_dec(data->data);
+		GPid pid = 0;
+		g_variant_get(vpid.get(), "(u)", &pid);
+
+		if (pid == data->app_pid_) {
+			/* Trying to send a message to the connection */
+			data->contact_app(G_DBUS_CONNECTION(object), name);
+		} else {
+			/* See if we can quit now */
+			data->connection_count_dec();
+		}
 	}
 
-	g_free(data->name);
-	g_free(data);
-
-	return;
+	delete this;
 }
 
 /* Starts to look for the PID and the connections for that PID */
-static void
-find_appid_pid (GDBusConnection * session, second_exec_t * data)
+void
+second_exec_t::find_appid_pid ()
 {
-	GError * error = NULL;
+	GError * error = nullptr;
 
 	/* List all the connections on dbus.  This sucks that we have to do
 	   this, but in the future we should add DBus API to do this lookup
 	   instead of having to do it with a bunch of requests */
-	GVariant * listnames = g_dbus_connection_call_sync(session,
+	auto listnames = unique_glib(g_dbus_connection_call_sync(bus_.get(),
 		"org.freedesktop.DBus",
 		"/",
 		"org.freedesktop.DBus",
 		"ListNames",
-		NULL,
+		nullptr,
 		G_VARIANT_TYPE("(as)"),
 		G_DBUS_CALL_FLAGS_NONE,
 		-1,
-		NULL,
-		&error);
+		nullptr,
+		&error));
 
-	if (error != NULL) {
+	if (error != nullptr) {
 		g_warning("Unable to get list of names from DBus: %s", error->message);
-		g_error_free(error);
+		g_clear_error(&error);
 		return;
 	}
 
 	g_debug("Got bus names");
-	ual_tracepoint(second_exec_got_dbus_names, data->appid);
+	ual_tracepoint(second_exec_got_dbus_names, appid_.c_str());
 
-	g_debug("Primary PID: %d", data->app_pid);
-	ual_tracepoint(second_exec_got_primary_pid, data->appid);
+	g_debug("Primary PID: %d", app_pid_);
+	ual_tracepoint(second_exec_got_primary_pid, appid_.c_str());
 
 	/* Get the names */
-	GVariant * names = g_variant_get_child_value(listnames, 0);
+	auto names = unique_glib(g_variant_get_child_value(listnames.get(), 0));
 	GVariantIter iter;
-	g_variant_iter_init(&iter, names);
-	gchar * name = NULL;
+	g_variant_iter_init(&iter, names.get());
+	gchar * name = nullptr;
 
 	while (g_variant_iter_loop(&iter, "s", &name)) {
 		/* We only want to ask each connection once, this makes that so */
 		if (!g_dbus_is_unique_name(name)) {
 			continue;
 		}
-		
-		get_pid_t * pid_data = g_new0(get_pid_t, 1);
-		pid_data->data = data;
-		pid_data->name = g_strdup(name);
-
-		ual_tracepoint(second_exec_request_pid, data->appid, pid_data->name);
-
-		/* Get the PIDs */
-		g_dbus_connection_call(session,
-			"org.freedesktop.DBus",
-			"/",
-			"org.freedesktop.DBus",
-			"GetConnectionUnixProcessID",
-			g_variant_new("(s)", name),
-			G_VARIANT_TYPE("(u)"),
-			G_DBUS_CALL_FLAGS_NONE,
-			-1,
-			NULL,
-			get_pid_cb, pid_data);
-
-		data->connections_open++;
+
+		ual_tracepoint(second_exec_request_pid, appid_.c_str(), name);
+
+		// FIXME This object deletes itself
+		new get_pid_t(string(name), bus_, shared_from_this());
+
+		connections_open++;
 	}
-
-	g_variant_unref(names);
-	g_variant_unref(listnames);
-
-	return;
-}
-
-gboolean
-second_exec (GDBusConnection * session, GCancellable * cancel, GPid pid, const gchar * app_id, const gchar * instance_id, gchar ** appuris)
-{
-	ual_tracepoint(second_exec_start, app_id);
-	GError * error = NULL;
-
-	/* Setup our continuation data */
-	second_exec_t * data = g_new0(second_exec_t, 1);
-	data->appid = g_strdup(app_id);
-	data->instanceid = g_strdup(instance_id);
-	data->input_uris = g_strdupv(appuris);
-	data->bus = g_object_ref(session);
-	data->app_pid = pid;
+}
+
+second_exec_t::second_exec_t(shared_ptr<GDBusConnection> bus, const string& appid, const string& instanceid, const vector<Application::URL>& input_uris, GPid app_pid) :
+		bus_(bus), appid_(appid), instanceid_(instanceid), input_uris_(input_uris), app_pid_(app_pid)
+{
+	// can't use for init, due to shared_from_this restriction
+}
+
+void
+second_exec_t::init()
+{
+	ual_tracepoint(second_exec_start, appid_.c_str());
 
 	/* Set up listening for the unfrozen signal from Unity */
-	data->signal = g_dbus_connection_signal_subscribe(session,
-		NULL, /* sender */
+	signal = managedDBusSignalConnection(g_dbus_connection_signal_subscribe(bus_.get(),
+		nullptr, /* sender */
 		"com.canonical.UbuntuAppLaunch", /* interface */
 		"UnityResumeResponse", /* signal */
 		"/", /* path */
-		app_id, /* arg0 */
+		appid_.c_str(), /* arg0 */
 		G_DBUS_SIGNAL_FLAGS_NONE,
-		unity_resume_cb, data,
-		NULL); /* user data destroy */
+		second_exec_t::unity_resume_cb, this,
+		nullptr), /* user data destroy */
+			bus_);
 
 	g_debug("Sending resume request");
-	ual_tracepoint(second_exec_emit_resume, app_id);
+	ual_tracepoint(second_exec_emit_resume, appid_.c_str());
+
+	GError * error = nullptr;
 
 	/* Send unfreeze to to Unity */
-	g_dbus_connection_emit_signal(session,
-		NULL, /* destination */
+	g_dbus_connection_emit_signal(bus_.get(),
+		nullptr, /* destination */
 		"/", /* path */
 		"com.canonical.UbuntuAppLaunch", /* interface */
 		"UnityResumeRequest", /* signal */
-		g_variant_new("(ss)", app_id, instance_id),
+		g_variant_new("(ss)", appid_.c_str(), instanceid_.c_str()),
 		&error);
 
 	/* Now we start a race, we try to get to the point of knowing who
 	   to send things to, and Unity is unfrezing it.  When both are
 	   done we can send something to the app */
-	data->unity_starttime = g_get_monotonic_time();
+	unity_starttime = g_get_monotonic_time();
 
-	if (error != NULL) {
+	if (error != nullptr) {
 		/* On error let's not wait for Unity */
 		g_warning("Unable to signal Unity: %s", error->message);
-		g_error_free(error);
-		error = NULL;
-		data->unity_starttime = 0;
+		g_clear_error(&error);
+		unity_starttime = 0;
 	}
 
 	/* If we've got something to give out, start looking for how */
-	if (data->input_uris != NULL) {
-		find_appid_pid(session, data);
+	if (!input_uris_.empty()) {
+		find_appid_pid();
 	} else {
 		g_debug("No URIs to send");
 	}
 
 	/* Loop and wait for everything to align */
-	if (data->connections_open == 0) {
-		if (data->unity_starttime == 0) {
-			second_exec_complete(data);
-		} else {
-			data->timer = thread_default_timeout(500, timer_cb, data);
+	if (connections_open == 0) {
+		if (unity_starttime != 0) {
+			timer = thread_default_timeout(500, timer_cb, this);
+			SECOND_EXEC_INSTANCES_.insert(make_pair(this, shared_from_this()));
 		}
 	}
-
-	return TRUE;
-}
-
-static void
-second_exec_complete (second_exec_t * data)
-{
-	GError * error = NULL;
-	ual_tracepoint(second_exec_emit_focus, data->appid);
+}
+
+void second_exec_t::finish()
+{
+	SECOND_EXEC_INSTANCES_.erase(this);
+}
+
+second_exec_t::~second_exec_t()
+{
+	GError * error = nullptr;
+	ual_tracepoint(second_exec_emit_focus, appid_.c_str());
 
 	/* Now that we're done sending the info to the app, we can ask
 	   Unity to focus the application. */
-	g_dbus_connection_emit_signal(data->bus,
-		NULL, /* destination */
+	g_dbus_connection_emit_signal(bus_.get(),
+		nullptr, /* destination */
 		"/", /* path */
 		"com.canonical.UbuntuAppLaunch", /* interface */
 		"UnityFocusRequest", /* signal */
-		g_variant_new("(ss)", data->appid, data->instanceid),
+		g_variant_new("(ss)", appid_.c_str(), instanceid_.c_str()),
 		&error);
 
-	if (error != NULL) {
+	if (error != nullptr)
+	{
 		g_warning("Unable to request focus to Unity: %s", error->message);
-		g_error_free(error);
-		error = NULL;
+		g_clear_error(&error);
 	}
 
 	/* Make sure the signal hits the bus */
-	g_dbus_connection_flush_sync(data->bus, NULL, &error);
+	g_dbus_connection_flush_sync(bus_.get(), nullptr, &error);
 	if (error != NULL) {
 		g_warning("Unable to flush session bus: %s", error->message);
-		g_error_free(error);
-		error = NULL;
+		g_clear_error(&error);
 	}
 
-	ual_tracepoint(second_exec_finish, data->appid);
+	ual_tracepoint(second_exec_finish, appid_.c_str());
 	g_debug("Second Exec complete");
-
-	/* Clean up */
-	if (data->signal != 0)
-		g_dbus_connection_signal_unsubscribe(data->bus, data->signal);
-
-	if (data->timer != NULL) {
-		g_source_destroy(data->timer);
-		g_source_unref(data->timer);
-	}
-	g_object_unref(data->bus);
-	if (data->app_data != NULL)
-		g_variant_unref(data->app_data);
-	g_free(data->appid);
-	g_free(data->instanceid);
-	g_strfreev(data->input_uris);
-	g_free(data->dbus_path);
-	g_free(data);
-
-	return;
+}
+
+}
+
+void
+second_exec (shared_ptr<GDBusConnection> session, shared_ptr<GCancellable> cancel, GPid pid, const string& app_id, const string& instance_id, const vector<Application::URL>& appuris)
+{
+	auto t = make_shared<second_exec_t>(
+		session,
+		app_id,
+		instance_id,
+		appuris,
+		pid
+	);
+
+	t->init();
+}
+
+}
 }

=== modified file 'libubuntu-app-launch/second-exec-core.h'
--- libubuntu-app-launch/second-exec-core.h	2016-12-14 23:03:15 +0000
+++ libubuntu-app-launch/second-exec-core.h	2017-04-05 12:08:51 +0000
@@ -1,6 +1,5 @@
-
 /*
- * Copyright 2013 Canonical Ltd.
+ * Copyright 2013-2017 Canonical Ltd.
  *
  * This program is free software: you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 3, as published
@@ -16,13 +15,25 @@
  *
  * Authors:
  *     Ted Gould <ted.gould@canonical.com>
+ *     Pete Woods <pete.woods@canonical.com>
  */
 
+
+#pragma once
+
 #include <gio/gio.h>
-
-G_BEGIN_DECLS
-
-gboolean second_exec (GDBusConnection * con, GCancellable * cancel, GPid pid, const gchar * app_id, const gchar * instance_id, gchar ** appuris);
-
-G_END_DECLS
-
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "application.h"
+
+namespace ubuntu
+{
+namespace app_launch
+{
+
+void second_exec (std::shared_ptr<GDBusConnection> con, std::shared_ptr<GCancellable> cancel, GPid pid, const std::string& app_id, const std::string& instance_id, const std::vector<Application::URL>& appuris);
+
+}
+}

