Merge lp:~ted/ubuntu-app-launch/jobs-signals into lp:ubuntu-app-launch
- jobs-signals
- Merge into trunk.17.04
Status: | Merged |
---|---|
Approved by: | Marcus Tomlinson |
Approved revision: | 280 |
Merged at revision: | 277 |
Proposed branch: | lp:~ted/ubuntu-app-launch/jobs-signals |
Merge into: | lp:ubuntu-app-launch |
Prerequisite: | lp:~ted/ubuntu-app-launch/abstract-jobs |
Diff against target: |
1659 lines (+754/-654) 7 files modified
libubuntu-app-launch/jobs-base.cpp (+356/-1) libubuntu-app-launch/jobs-base.h (+86/-1) libubuntu-app-launch/jobs-upstart.cpp (+258/-13) libubuntu-app-launch/jobs-upstart.h (+26/-0) libubuntu-app-launch/registry-impl.cpp (+0/-554) libubuntu-app-launch/registry-impl.h (+1/-78) libubuntu-app-launch/registry.cpp (+27/-7) |
To merge this branch: | bzr merge lp:~ted/ubuntu-app-launch/jobs-signals |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Marcus Tomlinson (community) | Approve | ||
unity-api-1-bot | continuous-integration | Needs Fixing | |
Review via email: mp+310587@code.launchpad.net |
Commit message
Move the signals into the jobs classes
Description of the change
This branch reshuffles the signal code from being in the registry implementation to being in the individual job implementations. Actually the base jobs handle the entirely internal UAL events, but the implementations can then implement things further that require getting events from the process manager. This branch just really reshuffles and renames code. No functional changes.
unity-api-1-bot (unity-api-1-bot) wrote : | # |
unity-api-1-bot (unity-api-1-bot) wrote : | # |
PASSED: Continuous integration, rev:279
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:280
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Marcus Tomlinson (marcustomlinson) wrote : | # |
Hmmm, so I've left an inline comment about a possible memory leak picked up by cppcheck. This led me to run a few valgrind checks over the tests, and there seem to be a fair bit of complaints. I'll mail you about that to keep this review concentrated.
Marcus Tomlinson (marcustomlinson) wrote : | # |
3 inline comments.
Marcus Tomlinson (marcustomlinson) wrote : | # |
Sorry, another 3 inline comments.
Ted Gould (ted) wrote : | # |
On Fri, 2017-01-20 at 09:10 +0000, Marcus Tomlinson wrote:
> Weird that this deleter is never called during the tests.
>
Yes, I think it must get optimized out to just a call to free since
everything else is basically making the type system happy. It seems
like a very aggressive optimization though.
Ted Gould (ted) wrote : | # |
On Fri, 2017-01-20 at 08:22 +0000, Marcus Tomlinson wrote:
> + managerEventData* focusdata = new managerEventDat
> > responsefunc};
> cppcheck is concerned about this focusdata pointer leaking memory.
> When is it ever deleted?
>
> >
> > +
> > + return g_dbus_
This function returns a handle, so then when that handle is used for
the unsubscribe the deleter is called. It can also get called if all
references to the connection get dropped.
Marcus Tomlinson (marcustomlinson) wrote : | # |
> On Fri, 2017-01-20 at 08:22 +0000, Marcus Tomlinson wrote:
> > + managerEventData* focusdata = new managerEventDat
> > > responsefunc};
> > cppcheck is concerned about this focusdata pointer leaking memory.
> > When is it ever deleted?
> >
> > >
> > > +
> > > + return g_dbus_
>
> This function returns a handle, so then when that handle is used for
> the unsubscribe the deleter is called. It can also get called if all
> references to the connection get dropped.
Yeah ok, I don't recall this line being flagged up by valgrind so I think we should be good here.
Marcus Tomlinson (marcustomlinson) wrote : | # |
Cool, looks good.
Preview Diff
1 | === modified file 'libubuntu-app-launch/jobs-base.cpp' |
2 | --- libubuntu-app-launch/jobs-base.cpp 2017-01-19 03:25:37 +0000 |
3 | +++ libubuntu-app-launch/jobs-base.cpp 2017-01-19 03:25:37 +0000 |
4 | @@ -37,7 +37,25 @@ |
5 | |
6 | Base::Base(const std::shared_ptr<Registry>& registry) |
7 | : registry_(registry) |
8 | -{ |
9 | + , dbus_(registry->impl->_dbus) |
10 | +{ |
11 | +} |
12 | + |
13 | +Base::~Base() |
14 | +{ |
15 | + auto dohandle = [&](guint& handle) { |
16 | + if (handle != 0) |
17 | + { |
18 | + g_dbus_connection_signal_unsubscribe(dbus_.get(), handle); |
19 | + handle = 0; |
20 | + } |
21 | + }; |
22 | + |
23 | + dohandle(handle_managerSignalFocus); |
24 | + dohandle(handle_managerSignalResume); |
25 | + dohandle(handle_managerSignalStarting); |
26 | + dohandle(handle_appPaused); |
27 | + dohandle(handle_appResumed); |
28 | } |
29 | |
30 | std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry) |
31 | @@ -45,6 +63,343 @@ |
32 | return std::make_shared<jobs::manager::Upstart>(registry); |
33 | } |
34 | |
35 | +/** Structure to track the data needed for upstart events. This cleans |
36 | + up the lifecycle as we're passing this as a pointer through the |
37 | + GLib calls. */ |
38 | +struct upstartEventData |
39 | +{ |
40 | + /** Keeping a weak pointer because the handle is held by |
41 | + the registry implementation. */ |
42 | + std::weak_ptr<Registry> weakReg; |
43 | +}; |
44 | + |
45 | +/** Core handler for pause and resume events. Includes turning the GVariant |
46 | + pid list into a std::vector and getting the application object. */ |
47 | +void Base::pauseEventEmitted(core::Signal<const std::shared_ptr<Application>&, |
48 | + const std::shared_ptr<Application::Instance>&, |
49 | + const std::vector<pid_t>&>& signal, |
50 | + const std::shared_ptr<GVariant>& params, |
51 | + const std::shared_ptr<Registry>& reg) |
52 | +{ |
53 | + std::vector<pid_t> pids; |
54 | + GVariant* vappid = g_variant_get_child_value(params.get(), 0); |
55 | + GVariant* vpids = g_variant_get_child_value(params.get(), 1); |
56 | + guint64 pid; |
57 | + GVariantIter thispid; |
58 | + g_variant_iter_init(&thispid, vpids); |
59 | + |
60 | + while (g_variant_iter_loop(&thispid, "t", &pid)) |
61 | + { |
62 | + pids.emplace_back(pid); |
63 | + } |
64 | + |
65 | + auto cappid = g_variant_get_string(vappid, NULL); |
66 | + auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
67 | + auto app = Application::create(appid, reg); |
68 | + |
69 | + /* TODO: Instance */ |
70 | + signal(app, {}, pids); |
71 | + |
72 | + g_variant_unref(vappid); |
73 | + g_variant_unref(vpids); |
74 | + |
75 | + return; |
76 | +} |
77 | + |
78 | +/** Grab the signal object for application paused. If we're not already listing for |
79 | + those signals this sets up a listener for them. */ |
80 | +core::Signal<const std::shared_ptr<Application>&, |
81 | + const std::shared_ptr<Application::Instance>&, |
82 | + const std::vector<pid_t>&>& |
83 | + Base::appPaused() |
84 | +{ |
85 | + std::call_once(flag_appPaused, [this]() { |
86 | + auto reg = registry_.lock(); |
87 | + |
88 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
89 | + upstartEventData* data = new upstartEventData{reg}; |
90 | + |
91 | + handle_appPaused = g_dbus_connection_signal_subscribe( |
92 | + reg->impl->_dbus.get(), /* bus */ |
93 | + nullptr, /* sender */ |
94 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
95 | + "ApplicationPaused", /* signal */ |
96 | + "/", /* path */ |
97 | + nullptr, /* arg0 */ |
98 | + G_DBUS_SIGNAL_FLAGS_NONE, |
99 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
100 | + gpointer user_data) -> void { |
101 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
102 | + auto reg = data->weakReg.lock(); |
103 | + |
104 | + if (!reg) |
105 | + { |
106 | + g_warning("Registry object invalid!"); |
107 | + return; |
108 | + } |
109 | + |
110 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
111 | + auto manager = std::dynamic_pointer_cast<Base>(reg->impl->jobs); |
112 | + manager->pauseEventEmitted(manager->sig_appPaused, sparams, reg); |
113 | + }, /* callback */ |
114 | + data, /* user data */ |
115 | + [](gpointer user_data) { |
116 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
117 | + delete data; |
118 | + }); /* user data destroy */ |
119 | + |
120 | + return true; |
121 | + }); |
122 | + }); |
123 | + |
124 | + return sig_appPaused; |
125 | +} |
126 | + |
127 | +/** Grab the signal object for application resumed. If we're not already listing for |
128 | + those signals this sets up a listener for them. */ |
129 | +core::Signal<const std::shared_ptr<Application>&, |
130 | + const std::shared_ptr<Application::Instance>&, |
131 | + const std::vector<pid_t>&>& |
132 | + Base::appResumed() |
133 | +{ |
134 | + std::call_once(flag_appResumed, [this]() { |
135 | + auto reg = registry_.lock(); |
136 | + |
137 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
138 | + upstartEventData* data = new upstartEventData{reg}; |
139 | + |
140 | + handle_appResumed = g_dbus_connection_signal_subscribe( |
141 | + reg->impl->_dbus.get(), /* bus */ |
142 | + nullptr, /* sender */ |
143 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
144 | + "ApplicationResumed", /* signal */ |
145 | + "/", /* path */ |
146 | + nullptr, /* arg0 */ |
147 | + G_DBUS_SIGNAL_FLAGS_NONE, |
148 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
149 | + gpointer user_data) -> void { |
150 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
151 | + auto reg = data->weakReg.lock(); |
152 | + |
153 | + if (!reg) |
154 | + { |
155 | + g_warning("Registry object invalid!"); |
156 | + return; |
157 | + } |
158 | + |
159 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
160 | + auto manager = std::dynamic_pointer_cast<Base>(reg->impl->jobs); |
161 | + manager->pauseEventEmitted(manager->sig_appResumed, sparams, reg); |
162 | + }, /* callback */ |
163 | + data, /* user data */ |
164 | + [](gpointer user_data) { |
165 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
166 | + delete data; |
167 | + }); /* user data destroy */ |
168 | + |
169 | + return true; |
170 | + }); |
171 | + }); |
172 | + |
173 | + return sig_appResumed; |
174 | +} |
175 | + |
176 | +/** Take the GVariant of parameters and turn them into an application and |
177 | + and instance. Easier to read in the smaller function */ |
178 | +std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Base::managerParams( |
179 | + const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg) |
180 | +{ |
181 | + std::shared_ptr<Application> app; |
182 | + std::shared_ptr<Application::Instance> instance; |
183 | + |
184 | + const gchar* cappid = nullptr; |
185 | + g_variant_get(params.get(), "(&s)", &cappid); |
186 | + |
187 | + auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
188 | + app = ubuntu::app_launch::Application::create(appid, reg); |
189 | + |
190 | + return std::make_tuple(app, instance); |
191 | +} |
192 | + |
193 | +/** Used to store data for manager based signal handlers. Has a link to the |
194 | + registry and the callback to use in a C++ style. */ |
195 | +struct managerEventData |
196 | +{ |
197 | + /* Keeping a weak pointer because the handle is held by |
198 | + the registry implementation. */ |
199 | + std::weak_ptr<Registry> weakReg; |
200 | + std::function<void(const std::shared_ptr<Registry>& reg, |
201 | + const std::shared_ptr<Application>& app, |
202 | + const std::shared_ptr<Application::Instance>& instance, |
203 | + const std::shared_ptr<GDBusConnection>&, |
204 | + const std::string&, |
205 | + const std::shared_ptr<GVariant>&)> |
206 | + func; |
207 | +}; |
208 | + |
209 | +/** Register for a signal for the manager. All of the signals needed this same |
210 | + code so it got pulled out into a function. Takes the same of the signal, the registry |
211 | + that we're using and a function to call after we've messaged all the parameters |
212 | + into being something C++-ish. */ |
213 | +guint Base::managerSignalHelper(const std::shared_ptr<Registry>& reg, |
214 | + const std::string& signalname, |
215 | + std::function<void(const std::shared_ptr<Registry>& reg, |
216 | + const std::shared_ptr<Application>& app, |
217 | + const std::shared_ptr<Application::Instance>& instance, |
218 | + const std::shared_ptr<GDBusConnection>&, |
219 | + const std::string&, |
220 | + const std::shared_ptr<GVariant>&)> responsefunc) |
221 | +{ |
222 | + managerEventData* focusdata = new managerEventData{reg, responsefunc}; |
223 | + |
224 | + return g_dbus_connection_signal_subscribe( |
225 | + reg->impl->_dbus.get(), /* bus */ |
226 | + nullptr, /* sender */ |
227 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
228 | + signalname.c_str(), /* signal */ |
229 | + "/", /* path */ |
230 | + nullptr, /* arg0 */ |
231 | + G_DBUS_SIGNAL_FLAGS_NONE, |
232 | + [](GDBusConnection* cconn, const gchar* csender, const gchar*, const gchar*, const gchar*, GVariant* params, |
233 | + gpointer user_data) -> void { |
234 | + auto data = reinterpret_cast<managerEventData*>(user_data); |
235 | + auto reg = data->weakReg.lock(); |
236 | + |
237 | + if (!reg) |
238 | + { |
239 | + g_warning("Registry object invalid!"); |
240 | + return; |
241 | + } |
242 | + |
243 | + /* If we're still conneted and the manager has been cleared |
244 | + we'll just be a no-op */ |
245 | + auto ljobs = std::dynamic_pointer_cast<Base>(reg->impl->jobs); |
246 | + if (!ljobs->manager_) |
247 | + { |
248 | + return; |
249 | + } |
250 | + |
251 | + auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
252 | + auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)), |
253 | + [](GDBusConnection* con) { g_clear_object(&con); }); |
254 | + std::string sender = csender; |
255 | + std::shared_ptr<Application> app; |
256 | + std::shared_ptr<Application::Instance> instance; |
257 | + |
258 | + std::tie(app, instance) = managerParams(vparams, reg); |
259 | + |
260 | + data->func(reg, app, instance, conn, sender, vparams); |
261 | + }, |
262 | + focusdata, |
263 | + [](gpointer user_data) { |
264 | + auto data = reinterpret_cast<managerEventData*>(user_data); |
265 | + delete data; |
266 | + }); /* user data destroy */ |
267 | +} |
268 | + |
269 | +/** Set the manager for the registry. This includes tracking the pointer |
270 | + as well as setting up the signals to call back into the manager. The |
271 | + signals are only setup once per registry even if the manager is cleared |
272 | + and changed again. They will just be no-op's in those cases. |
273 | +*/ |
274 | +void Base::setManager(std::shared_ptr<Registry::Manager> manager) |
275 | +{ |
276 | + if (manager_) |
277 | + { |
278 | + throw std::runtime_error("Already have a manager and trying to set another"); |
279 | + } |
280 | + |
281 | + g_debug("Setting a new manager"); |
282 | + manager_ = manager; |
283 | + |
284 | + std::call_once(flag_managerSignals, [this]() { |
285 | + auto reg = registry_.lock(); |
286 | + |
287 | + if (!reg) |
288 | + { |
289 | + g_warning("Registry object invalid!"); |
290 | + return; |
291 | + } |
292 | + |
293 | + if (!reg->impl->thread.executeOnThread<bool>([this, reg]() { |
294 | + handle_managerSignalFocus = managerSignalHelper( |
295 | + reg, "UnityFocusRequest", |
296 | + [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
297 | + const std::shared_ptr<Application::Instance>& instance, |
298 | + const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
299 | + const std::shared_ptr<GVariant>& params) { |
300 | + /* Nothing to do today */ |
301 | + std::dynamic_pointer_cast<Base>(reg->impl->jobs) |
302 | + ->manager_->focusRequest(app, instance, [](bool response) { |
303 | + /* NOTE: We have no clue what thread this is gonna be |
304 | + executed on, but since we're just talking to the GDBus |
305 | + thread it isn't an issue today. Be careful in changing |
306 | + this code. */ |
307 | + }); |
308 | + }); |
309 | + handle_managerSignalStarting = managerSignalHelper( |
310 | + reg, "UnityStartingBroadcast", |
311 | + [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
312 | + const std::shared_ptr<Application::Instance>& instance, |
313 | + const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
314 | + const std::shared_ptr<GVariant>& params) { |
315 | + |
316 | + std::dynamic_pointer_cast<Base>(reg->impl->jobs) |
317 | + ->manager_->startingRequest(app, instance, [conn, sender, params](bool response) { |
318 | + /* NOTE: We have no clue what thread this is gonna be |
319 | + executed on, but since we're just talking to the GDBus |
320 | + thread it isn't an issue today. Be careful in changing |
321 | + this code. */ |
322 | + if (response) |
323 | + { |
324 | + g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
325 | + "/", /* path */ |
326 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
327 | + "UnityStartingSignal", /* signal */ |
328 | + params.get(), /* params, the same */ |
329 | + nullptr); /* error */ |
330 | + } |
331 | + }); |
332 | + }); |
333 | + handle_managerSignalResume = managerSignalHelper( |
334 | + reg, "UnityResumeRequest", |
335 | + [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
336 | + const std::shared_ptr<Application::Instance>& instance, |
337 | + const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
338 | + const std::shared_ptr<GVariant>& params) { |
339 | + std::dynamic_pointer_cast<Base>(reg->impl->jobs) |
340 | + ->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) { |
341 | + /* NOTE: We have no clue what thread this is gonna be |
342 | + executed on, but since we're just talking to the GDBus |
343 | + thread it isn't an issue today. Be careful in changing |
344 | + this code. */ |
345 | + if (response) |
346 | + { |
347 | + g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
348 | + "/", /* path */ |
349 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
350 | + "UnityResumeResponse", /* signal */ |
351 | + params.get(), /* params, the same */ |
352 | + nullptr); /* error */ |
353 | + } |
354 | + }); |
355 | + }); |
356 | + |
357 | + return true; |
358 | + })) |
359 | + { |
360 | + g_warning("Unable to install manager signals"); |
361 | + } |
362 | + }); |
363 | +} |
364 | + |
365 | +/** Clear the manager pointer */ |
366 | +void Base::clearManager() |
367 | +{ |
368 | + g_debug("Clearing the manager"); |
369 | + manager_.reset(); |
370 | +} |
371 | + |
372 | } // namespace manager |
373 | |
374 | namespace instance |
375 | |
376 | === modified file 'libubuntu-app-launch/jobs-base.h' |
377 | --- libubuntu-app-launch/jobs-base.h 2017-01-19 03:25:37 +0000 |
378 | +++ libubuntu-app-launch/jobs-base.h 2017-01-19 03:25:37 +0000 |
379 | @@ -18,7 +18,12 @@ |
380 | */ |
381 | |
382 | #pragma once |
383 | + |
384 | #include "application.h" |
385 | +#include "registry.h" |
386 | + |
387 | +#include <core/signal.h> |
388 | +#include <gio/gio.h> |
389 | |
390 | namespace ubuntu |
391 | { |
392 | @@ -88,7 +93,7 @@ |
393 | { |
394 | public: |
395 | Base(const std::shared_ptr<Registry>& registry); |
396 | - virtual ~Base() = default; |
397 | + virtual ~Base(); |
398 | |
399 | virtual std::shared_ptr<Application::Instance> launch( |
400 | const AppID& appId, |
401 | @@ -109,8 +114,88 @@ |
402 | |
403 | static std::shared_ptr<Base> determineFactory(std::shared_ptr<Registry> registry); |
404 | |
405 | + /* Signals to apps */ |
406 | + virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& |
407 | + appStarted() = 0; |
408 | + virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& |
409 | + appStopped() = 0; |
410 | + virtual core::Signal<const std::shared_ptr<Application>&, |
411 | + const std::shared_ptr<Application::Instance>&, |
412 | + Registry::FailureType>& |
413 | + appFailed() = 0; |
414 | + virtual core::Signal<const std::shared_ptr<Application>&, |
415 | + const std::shared_ptr<Application::Instance>&, |
416 | + const std::vector<pid_t>&>& |
417 | + appPaused(); |
418 | + virtual core::Signal<const std::shared_ptr<Application>&, |
419 | + const std::shared_ptr<Application::Instance>&, |
420 | + const std::vector<pid_t>&>& |
421 | + appResumed(); |
422 | + |
423 | + /* App manager */ |
424 | + virtual void setManager(std::shared_ptr<Registry::Manager> manager); |
425 | + virtual void clearManager(); |
426 | + |
427 | protected: |
428 | + /** A link to the registry */ |
429 | std::weak_ptr<Registry> registry_; |
430 | + |
431 | + /** The DBus connection we're connecting to */ |
432 | + std::shared_ptr<GDBusConnection> dbus_; |
433 | + |
434 | + /** Application manager instance */ |
435 | + std::shared_ptr<Registry::Manager> manager_; |
436 | + |
437 | + /** Signal object for applications started */ |
438 | + core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&> sig_appStarted; |
439 | + /** Signal object for applications stopped */ |
440 | + core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&> sig_appStopped; |
441 | + /** Signal object for applications failed */ |
442 | + core::Signal<const std::shared_ptr<Application>&, |
443 | + const std::shared_ptr<Application::Instance>&, |
444 | + Registry::FailureType> |
445 | + sig_appFailed; |
446 | + /** Signal object for applications paused */ |
447 | + core::Signal<const std::shared_ptr<Application>&, |
448 | + const std::shared_ptr<Application::Instance>&, |
449 | + const std::vector<pid_t>&> |
450 | + sig_appPaused; |
451 | + /** Signal object for applications resumed */ |
452 | + core::Signal<const std::shared_ptr<Application>&, |
453 | + const std::shared_ptr<Application::Instance>&, |
454 | + const std::vector<pid_t>&> |
455 | + sig_appResumed; |
456 | + |
457 | +private: |
458 | + guint handle_managerSignalFocus{0}; /**< GDBus signal watcher handle for app focused signal */ |
459 | + guint handle_managerSignalResume{0}; /**< GDBus signal watcher handle for app resumed signal */ |
460 | + guint handle_managerSignalStarting{0}; /**< GDBus signal watcher handle for app starting signal */ |
461 | + guint handle_appPaused{0}; /**< GDBus signal watcher handle for app paused signal */ |
462 | + guint handle_appResumed{0}; /**< GDBus signal watcher handle for app resumed signal */ |
463 | + |
464 | + std::once_flag flag_managerSignals; /**< Variable to track to see if signal handlers are installed for the manager |
465 | + signals of focused, resumed and starting */ |
466 | + std::once_flag |
467 | + flag_appPaused; /**< Variable to track to see if signal handlers are installed for application paused */ |
468 | + std::once_flag flag_appResumed; /**< Variable to track to see if signal handlers are installed for application |
469 | + resumed */ |
470 | + |
471 | + void pauseEventEmitted(core::Signal<const std::shared_ptr<Application>&, |
472 | + const std::shared_ptr<Application::Instance>&, |
473 | + const std::vector<pid_t>&>& signal, |
474 | + const std::shared_ptr<GVariant>& params, |
475 | + const std::shared_ptr<Registry>& reg); |
476 | + |
477 | + static std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> managerParams( |
478 | + const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg); |
479 | + static guint managerSignalHelper(const std::shared_ptr<Registry>& reg, |
480 | + const std::string& signalname, |
481 | + std::function<void(const std::shared_ptr<Registry>& reg, |
482 | + const std::shared_ptr<Application>& app, |
483 | + const std::shared_ptr<Application::Instance>& instance, |
484 | + const std::shared_ptr<GDBusConnection>&, |
485 | + const std::string&, |
486 | + const std::shared_ptr<GVariant>&)> responsefunc); |
487 | }; |
488 | |
489 | } // namespace manager |
490 | |
491 | === modified file 'libubuntu-app-launch/jobs-upstart.cpp' |
492 | --- libubuntu-app-launch/jobs-upstart.cpp 2017-01-19 03:25:37 +0000 |
493 | +++ libubuntu-app-launch/jobs-upstart.cpp 2017-01-19 03:25:37 +0000 |
494 | @@ -108,7 +108,7 @@ |
495 | } |
496 | |
497 | g_debug("Getting instance by name: %s", instance_.c_str()); |
498 | - GVariant* vinstance_path = |
499 | + auto vinstance_path = |
500 | g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* connection */ |
501 | DBUS_SERVICE_UPSTART, /* service */ |
502 | jobpath.c_str(), /* object path */ |
503 | @@ -145,7 +145,7 @@ |
504 | return 0; |
505 | } |
506 | |
507 | - GVariant* props_tuple = |
508 | + auto props_tuple = |
509 | g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* connection */ |
510 | DBUS_SERVICE_UPSTART, /* service */ |
511 | instance_path.c_str(), /* object path */ |
512 | @@ -166,15 +166,15 @@ |
513 | return 0; |
514 | } |
515 | |
516 | - GVariant* props_dict = g_variant_get_child_value(props_tuple, 0); |
517 | + auto props_dict = g_variant_get_child_value(props_tuple, 0); |
518 | |
519 | pid_t retval = 0; |
520 | - GVariant* processes = g_variant_lookup_value(props_dict, "processes", G_VARIANT_TYPE("a(si)")); |
521 | + auto processes = g_variant_lookup_value(props_dict, "processes", G_VARIANT_TYPE("a(si)")); |
522 | if (processes != nullptr && g_variant_n_children(processes) > 0) |
523 | { |
524 | |
525 | - GVariant* first_entry = g_variant_get_child_value(processes, 0); |
526 | - GVariant* pidv = g_variant_get_child_value(first_entry, 1); |
527 | + auto first_entry = g_variant_get_child_value(processes, 0); |
528 | + auto pidv = g_variant_get_child_value(first_entry, 1); |
529 | |
530 | retval = g_variant_get_int32(pidv); |
531 | |
532 | @@ -267,7 +267,7 @@ |
533 | g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); /* wait */ |
534 | |
535 | GError* error = nullptr; |
536 | - GVariant* stop_variant = |
537 | + auto stop_variant = |
538 | g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* Dbus */ |
539 | DBUS_SERVICE_UPSTART, /* Upstart name */ |
540 | jobpath.c_str(), /* path */ |
541 | @@ -499,6 +499,17 @@ |
542 | |
543 | Upstart::~Upstart() |
544 | { |
545 | + auto dohandle = [&](guint& handle) { |
546 | + if (handle != 0) |
547 | + { |
548 | + g_dbus_connection_signal_unsubscribe(dbus_.get(), handle); |
549 | + handle = 0; |
550 | + } |
551 | + }; |
552 | + |
553 | + dohandle(handle_appStarted); |
554 | + dohandle(handle_appStopped); |
555 | + dohandle(handle_appFailed); |
556 | } |
557 | |
558 | /** Launch an application and create a new Upstart instance object to track |
559 | @@ -523,6 +534,13 @@ |
560 | return {}; |
561 | |
562 | auto registry = registry_.lock(); |
563 | + |
564 | + if (!registry) |
565 | + { |
566 | + g_warning("Registry object invalid!"); |
567 | + return {}; |
568 | + } |
569 | + |
570 | return registry->impl->thread.executeOnThread<std::shared_ptr<instance::Upstart>>( |
571 | [&]() -> std::shared_ptr<instance::Upstart> { |
572 | auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry->impl->jobs); |
573 | @@ -672,6 +690,233 @@ |
574 | return vect; |
575 | } |
576 | |
577 | +/** Structure to track the data needed for upstart events. This cleans |
578 | + up the lifecycle as we're passing this as a pointer through the |
579 | + GLib calls. */ |
580 | +struct upstartEventData |
581 | +{ |
582 | + /** Keeping a weak pointer because the handle is held by |
583 | + the registry implementation. */ |
584 | + std::weak_ptr<Registry> weakReg; |
585 | +}; |
586 | + |
587 | +/** Regex to parse the JOB environment variable from Upstart */ |
588 | +const std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"}; |
589 | +/** Regex to parse the INSTANCE environment variable from Upstart */ |
590 | +const std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"}; |
591 | + |
592 | +/** Core of most of the events that come from Upstart directly. Includes parsing of the |
593 | + Upstart event environment and calling the appropriate signal with the right Application |
594 | + object and eventually its instance */ |
595 | +void Upstart::upstartEventEmitted( |
596 | + core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal, |
597 | + std::shared_ptr<GVariant> params, |
598 | + const std::shared_ptr<Registry>& reg) |
599 | +{ |
600 | + std::string jobname; |
601 | + std::string sappid; |
602 | + std::string instance; |
603 | + |
604 | + gchar* env = nullptr; |
605 | + auto envs = g_variant_get_child_value(params.get(), 1); |
606 | + GVariantIter iter; |
607 | + g_variant_iter_init(&iter, envs); |
608 | + |
609 | + while (g_variant_iter_loop(&iter, "s", &env)) |
610 | + { |
611 | + std::smatch match; |
612 | + std::string senv = env; |
613 | + |
614 | + if (std::regex_match(senv, match, jobenv_regex)) |
615 | + { |
616 | + jobname = match[1].str(); |
617 | + } |
618 | + else if (std::regex_match(senv, match, instanceenv_regex)) |
619 | + { |
620 | + sappid = match[1].str(); |
621 | + instance = match[2].str(); |
622 | + } |
623 | + } |
624 | + |
625 | + g_variant_unref(envs); |
626 | + |
627 | + if (jobname.empty()) |
628 | + { |
629 | + return; |
630 | + } |
631 | + |
632 | + g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str()); |
633 | + |
634 | + auto appid = AppID::find(reg, sappid); |
635 | + auto app = Application::create(appid, reg); |
636 | + |
637 | + // TODO: Figure otu creating instances |
638 | + |
639 | + signal(app, {}); |
640 | +} |
641 | + |
642 | +/** Grab the signal object for application startup. If we're not already listing for |
643 | + those signals this sets up a listener for them. */ |
644 | +core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Upstart::appStarted() |
645 | +{ |
646 | + std::call_once(flag_appStarted, [this]() { |
647 | + auto reg = registry_.lock(); |
648 | + |
649 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
650 | + upstartEventData* data = new upstartEventData{reg}; |
651 | + |
652 | + handle_appStarted = g_dbus_connection_signal_subscribe( |
653 | + reg->impl->_dbus.get(), /* bus */ |
654 | + nullptr, /* sender */ |
655 | + DBUS_INTERFACE_UPSTART, /* interface */ |
656 | + "EventEmitted", /* signal */ |
657 | + DBUS_PATH_UPSTART, /* path */ |
658 | + "started", /* arg0 */ |
659 | + G_DBUS_SIGNAL_FLAGS_NONE, |
660 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
661 | + gpointer user_data) { |
662 | + auto data = static_cast<upstartEventData*>(user_data); |
663 | + auto reg = data->weakReg.lock(); |
664 | + |
665 | + if (!reg) |
666 | + { |
667 | + g_warning("Registry object invalid!"); |
668 | + return; |
669 | + } |
670 | + |
671 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
672 | + auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs); |
673 | + upstart->upstartEventEmitted(upstart->sig_appStarted, sparams, reg); |
674 | + }, /* callback */ |
675 | + data, /* user data */ |
676 | + [](gpointer user_data) { |
677 | + auto data = static_cast<upstartEventData*>(user_data); |
678 | + delete data; |
679 | + }); /* user data destroy */ |
680 | + |
681 | + return true; |
682 | + }); |
683 | + }); |
684 | + |
685 | + return sig_appStarted; |
686 | +} |
687 | + |
688 | +/** Grab the signal object for application stopping. If we're not already listing for |
689 | + those signals this sets up a listener for them. */ |
690 | +core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Upstart::appStopped() |
691 | +{ |
692 | + std::call_once(flag_appStopped, [this]() { |
693 | + auto reg = registry_.lock(); |
694 | + |
695 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
696 | + upstartEventData* data = new upstartEventData{reg}; |
697 | + |
698 | + handle_appStopped = g_dbus_connection_signal_subscribe( |
699 | + reg->impl->_dbus.get(), /* bus */ |
700 | + nullptr, /* sender */ |
701 | + DBUS_INTERFACE_UPSTART, /* interface */ |
702 | + "EventEmitted", /* signal */ |
703 | + DBUS_PATH_UPSTART, /* path */ |
704 | + "stopped", /* arg0 */ |
705 | + G_DBUS_SIGNAL_FLAGS_NONE, |
706 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
707 | + gpointer user_data) { |
708 | + auto data = static_cast<upstartEventData*>(user_data); |
709 | + auto reg = data->weakReg.lock(); |
710 | + |
711 | + if (!reg) |
712 | + { |
713 | + g_warning("Registry object invalid!"); |
714 | + return; |
715 | + } |
716 | + |
717 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
718 | + auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs); |
719 | + upstart->upstartEventEmitted(upstart->sig_appStopped, sparams, reg); |
720 | + }, /* callback */ |
721 | + data, /* user data */ |
722 | + [](gpointer user_data) { |
723 | + auto data = static_cast<upstartEventData*>(user_data); |
724 | + delete data; |
725 | + }); /* user data destroy */ |
726 | + |
727 | + return true; |
728 | + }); |
729 | + }); |
730 | + |
731 | + return sig_appStopped; |
732 | +} |
733 | + |
734 | +/** Grab the signal object for application failing. If we're not already listing for |
735 | + those signals this sets up a listener for them. */ |
736 | +core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>& |
737 | + Upstart::appFailed() |
738 | +{ |
739 | + std::call_once(flag_appFailed, [this]() { |
740 | + auto reg = registry_.lock(); |
741 | + |
742 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
743 | + upstartEventData* data = new upstartEventData{reg}; |
744 | + |
745 | + handle_appFailed = g_dbus_connection_signal_subscribe( |
746 | + reg->impl->_dbus.get(), /* bus */ |
747 | + nullptr, /* sender */ |
748 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
749 | + "ApplicationFailed", /* signal */ |
750 | + "/", /* path */ |
751 | + nullptr, /* arg0 */ |
752 | + G_DBUS_SIGNAL_FLAGS_NONE, |
753 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
754 | + gpointer user_data) { |
755 | + auto data = static_cast<upstartEventData*>(user_data); |
756 | + auto reg = data->weakReg.lock(); |
757 | + |
758 | + if (!reg) |
759 | + { |
760 | + g_warning("Registry object invalid!"); |
761 | + return; |
762 | + } |
763 | + |
764 | + const gchar* sappid = nullptr; |
765 | + const gchar* typestr = nullptr; |
766 | + |
767 | + Registry::FailureType type = Registry::FailureType::CRASH; |
768 | + g_variant_get(params, "(&s&s)", &sappid, &typestr); |
769 | + |
770 | + if (g_strcmp0("crash", typestr) == 0) |
771 | + { |
772 | + type = Registry::FailureType::CRASH; |
773 | + } |
774 | + else if (g_strcmp0("start-failure", typestr) == 0) |
775 | + { |
776 | + type = Registry::FailureType::START_FAILURE; |
777 | + } |
778 | + else |
779 | + { |
780 | + g_warning("Application failure type '%s' unknown, reporting as a crash", typestr); |
781 | + } |
782 | + |
783 | + auto appid = AppID::find(reg, sappid); |
784 | + auto app = Application::create(appid, reg); |
785 | + |
786 | + /* TODO: Instance issues */ |
787 | + |
788 | + auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs); |
789 | + upstart->sig_appFailed(app, {}, type); |
790 | + }, /* callback */ |
791 | + data, /* user data */ |
792 | + [](gpointer user_data) { |
793 | + auto data = static_cast<upstartEventData*>(user_data); |
794 | + delete data; |
795 | + }); /* user data destroy */ |
796 | + |
797 | + return true; |
798 | + }); |
799 | + }); |
800 | + |
801 | + return sig_appFailed; |
802 | +} |
803 | + |
804 | /** Initialize the CGManager connection, including a timeout to disconnect |
805 | as CGManager doesn't free resources entirely well. So it's better if |
806 | we connect and disconnect occationally */ |
807 | @@ -741,9 +986,9 @@ |
808 | |
809 | g_debug("Looking for cg manager '%s' group '%s'", name, groupname.c_str()); |
810 | |
811 | - GVariant* vtpids = g_dbus_connection_call_sync( |
812 | + auto vtpids = g_dbus_connection_call_sync( |
813 | lmanager.get(), /* connection */ |
814 | - name, /* bus name for direct connection is NULL */ |
815 | + name, /* bus name for direct connection is nullptr */ |
816 | "/org/linuxcontainers/cgmanager", /* object */ |
817 | "org.linuxcontainers.cgmanager0_0", /* interface */ |
818 | "GetTasksRecursive", /* method */ |
819 | @@ -792,7 +1037,7 @@ |
820 | auto registry = registry_.lock(); |
821 | auto path = registry->impl->thread.executeOnThread<std::string>([this, &job, ®istry]() -> std::string { |
822 | GError* error = nullptr; |
823 | - GVariant* job_path_variant = |
824 | + auto job_path_variant = |
825 | g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */ |
826 | DBUS_SERVICE_UPSTART, /* service */ |
827 | DBUS_PATH_UPSTART, /* path */ |
828 | @@ -848,7 +1093,7 @@ |
829 | return registry->impl->thread.executeOnThread<std::list<std::string>>( |
830 | [this, &job, &jobpath, ®istry]() -> std::list<std::string> { |
831 | GError* error = nullptr; |
832 | - GVariant* instance_tuple = |
833 | + auto instance_tuple = |
834 | g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */ |
835 | DBUS_SERVICE_UPSTART, /* service */ |
836 | jobpath.c_str(), /* object path */ |
837 | @@ -883,7 +1128,7 @@ |
838 | |
839 | while (g_variant_iter_loop(&instance_iter, "&o", &instance_path)) |
840 | { |
841 | - GVariant* props_tuple = |
842 | + auto props_tuple = |
843 | g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */ |
844 | DBUS_SERVICE_UPSTART, /* service */ |
845 | instance_path, /* object path */ |
846 | @@ -909,7 +1154,7 @@ |
847 | auto namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING); |
848 | if (namev != nullptr) |
849 | { |
850 | - auto name = g_variant_get_string(namev, NULL); |
851 | + auto name = g_variant_get_string(namev, nullptr); |
852 | g_debug("Adding instance for job '%s': %s", job.c_str(), name); |
853 | instances.push_back(name); |
854 | g_variant_unref(namev); |
855 | |
856 | === modified file 'libubuntu-app-launch/jobs-upstart.h' |
857 | --- libubuntu-app-launch/jobs-upstart.h 2017-01-19 03:25:37 +0000 |
858 | +++ libubuntu-app-launch/jobs-upstart.h 2017-01-19 03:25:37 +0000 |
859 | @@ -54,6 +54,16 @@ |
860 | |
861 | virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) override; |
862 | |
863 | + /* Signals to apps */ |
864 | + virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& |
865 | + appStarted() override; |
866 | + virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& |
867 | + appStopped() override; |
868 | + virtual core::Signal<const std::shared_ptr<Application>&, |
869 | + const std::shared_ptr<Application::Instance>&, |
870 | + Registry::FailureType>& |
871 | + appFailed() override; |
872 | + |
873 | std::vector<pid_t> pidsFromCgroup(const std::string& jobpath); |
874 | |
875 | std::list<std::string> upstartInstancesForJob(const std::string& job); |
876 | @@ -67,6 +77,22 @@ |
877 | /** Getting the Upstart job path is relatively expensive in |
878 | that it requires a DBus call. Worth keeping a cache of. */ |
879 | std::map<std::string, std::string> upstartJobPathCache_; |
880 | + |
881 | + guint handle_appStarted{0}; /**< GDBus signal watcher handle for app started signal */ |
882 | + guint handle_appStopped{0}; /**< GDBus signal watcher handle for app stopped signal */ |
883 | + guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */ |
884 | + |
885 | + std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application |
886 | + started */ |
887 | + std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application |
888 | + stopped */ |
889 | + std::once_flag |
890 | + flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */ |
891 | + |
892 | + void upstartEventEmitted( |
893 | + core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal, |
894 | + std::shared_ptr<GVariant> params, |
895 | + const std::shared_ptr<Registry>& reg); |
896 | }; |
897 | |
898 | } // namespace manager |
899 | |
900 | === modified file 'libubuntu-app-launch/registry-impl.cpp' |
901 | --- libubuntu-app-launch/registry-impl.cpp 2017-01-19 03:25:37 +0000 |
902 | +++ libubuntu-app-launch/registry-impl.cpp 2017-01-19 03:25:37 +0000 |
903 | @@ -36,23 +36,6 @@ |
904 | zgLog_.reset(); |
905 | jobs.reset(); |
906 | |
907 | - auto dohandle = [&](guint& handle) { |
908 | - if (handle != 0) |
909 | - { |
910 | - g_dbus_connection_signal_unsubscribe(_dbus.get(), handle); |
911 | - handle = 0; |
912 | - } |
913 | - }; |
914 | - |
915 | - dohandle(handle_appStarted); |
916 | - dohandle(handle_appStopped); |
917 | - dohandle(handle_appFailed); |
918 | - dohandle(handle_appPaused); |
919 | - dohandle(handle_appResumed); |
920 | - dohandle(handle_managerSignalFocus); |
921 | - dohandle(handle_managerSignalResume); |
922 | - dohandle(handle_managerSignalStarting); |
923 | - |
924 | if (_dbus) |
925 | g_dbus_connection_flush_sync(_dbus.get(), nullptr, nullptr); |
926 | _dbus.reset(); |
927 | @@ -290,208 +273,6 @@ |
928 | return _iconFinders[basePath]; |
929 | } |
930 | |
931 | -/** Structure to track the data needed for upstart events. This cleans |
932 | - up the lifecycle as we're passing this as a pointer through the |
933 | - GLib calls. */ |
934 | -struct upstartEventData |
935 | -{ |
936 | - /** Keeping a weak pointer because the handle is held by |
937 | - the registry implementation. */ |
938 | - std::weak_ptr<Registry> weakReg; |
939 | -}; |
940 | - |
941 | -/** Take the GVariant of parameters and turn them into an application and |
942 | - and instance. Easier to read in the smaller function */ |
943 | -std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Registry::Impl::managerParams( |
944 | - const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg) |
945 | -{ |
946 | - std::shared_ptr<Application> app; |
947 | - std::shared_ptr<Application::Instance> instance; |
948 | - |
949 | - const gchar* cappid = nullptr; |
950 | - g_variant_get(params.get(), "(&s)", &cappid); |
951 | - |
952 | - if (cappid != nullptr) |
953 | - { |
954 | - auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
955 | - app = ubuntu::app_launch::Application::create(appid, reg); |
956 | - } |
957 | - |
958 | - return std::make_tuple(app, instance); |
959 | -} |
960 | - |
961 | -/** Used to store data for manager based signal handlers. Has a link to the |
962 | - registry and the callback to use in a C++ style. */ |
963 | -struct managerEventData |
964 | -{ |
965 | - /* Keeping a weak pointer because the handle is held by |
966 | - the registry implementation. */ |
967 | - std::weak_ptr<Registry> weakReg; |
968 | - std::function<void(const std::shared_ptr<Registry>& reg, |
969 | - const std::shared_ptr<Application>& app, |
970 | - const std::shared_ptr<Application::Instance>& instance, |
971 | - const std::shared_ptr<GDBusConnection>& dbus, |
972 | - const std::string& sender, |
973 | - const std::shared_ptr<GVariant>& params)> |
974 | - func; |
975 | -}; |
976 | - |
977 | -/** Register for a signal for the manager. All of the signals needed this same |
978 | - code so it got pulled out into a function. Takes the same of the signal, the registry |
979 | - that we're using and a function to call after we've messaged all the parameters |
980 | - into being something C++-ish. */ |
981 | -guint Registry::Impl::managerSignalHelper(const std::shared_ptr<Registry>& reg, |
982 | - const std::string& signalname, |
983 | - std::function<void(const std::shared_ptr<Registry>& reg, |
984 | - const std::shared_ptr<Application>& app, |
985 | - const std::shared_ptr<Application::Instance>& instance, |
986 | - const std::shared_ptr<GDBusConnection>& dbus, |
987 | - const std::string& sender, |
988 | - const std::shared_ptr<GVariant>& params)> responsefunc) |
989 | -{ |
990 | - auto focusdata = new managerEventData{reg, responsefunc}; |
991 | - |
992 | - return g_dbus_connection_signal_subscribe( |
993 | - reg->impl->_dbus.get(), /* bus */ |
994 | - nullptr, /* sender */ |
995 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
996 | - signalname.c_str(), /* signal */ |
997 | - "/", /* path */ |
998 | - nullptr, /* arg0 */ |
999 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1000 | - [](GDBusConnection* cconn, const gchar* csender, const gchar*, const gchar*, const gchar*, GVariant* params, |
1001 | - gpointer user_data) { |
1002 | - auto data = static_cast<managerEventData*>(user_data); |
1003 | - auto reg = data->weakReg.lock(); |
1004 | - |
1005 | - if (!reg) |
1006 | - { |
1007 | - g_warning("Registry object invalid!"); |
1008 | - return; |
1009 | - } |
1010 | - |
1011 | - /* If we're still connected and the manager has been cleared |
1012 | - we'll just be a no-op */ |
1013 | - if (!reg->impl->manager_) |
1014 | - { |
1015 | - return; |
1016 | - } |
1017 | - |
1018 | - auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
1019 | - auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)), |
1020 | - [](GDBusConnection* con) { g_clear_object(&con); }); |
1021 | - std::string sender = csender; |
1022 | - std::shared_ptr<Application> app; |
1023 | - std::shared_ptr<Application::Instance> instance; |
1024 | - |
1025 | - std::tie(app, instance) = managerParams(vparams, reg); |
1026 | - |
1027 | - data->func(reg, app, instance, conn, sender, vparams); |
1028 | - }, |
1029 | - focusdata, |
1030 | - [](gpointer user_data) { |
1031 | - auto data = static_cast<managerEventData*>(user_data); |
1032 | - delete data; |
1033 | - }); /* user data destroy */ |
1034 | -} |
1035 | - |
1036 | -/** Set the manager for the registry. This includes tracking the pointer |
1037 | - as well as setting up the signals to call back into the manager. The |
1038 | - signals are only setup once per registry even if the manager is cleared |
1039 | - and changed again. They will just be no-op's in those cases. |
1040 | -*/ |
1041 | -void Registry::Impl::setManager(const std::shared_ptr<Registry::Manager>& manager, const std::shared_ptr<Registry>& reg) |
1042 | -{ |
1043 | - if (!reg) |
1044 | - { |
1045 | - throw std::invalid_argument("Passed null registry to setManager()"); |
1046 | - } |
1047 | - |
1048 | - if (reg->impl->manager_) |
1049 | - { |
1050 | - throw std::logic_error("Already have a manager and trying to set another"); |
1051 | - } |
1052 | - |
1053 | - g_debug("Setting a new manager"); |
1054 | - reg->impl->manager_ = manager; |
1055 | - |
1056 | - std::call_once(reg->impl->flag_managerSignals, [reg]() { |
1057 | - if (!reg->impl->thread.executeOnThread<bool>([reg]() { |
1058 | - reg->impl->handle_managerSignalFocus = managerSignalHelper( |
1059 | - reg, "UnityFocusRequest", |
1060 | - [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
1061 | - const std::shared_ptr<Application::Instance>& instance, |
1062 | - const std::shared_ptr<GDBusConnection>& /* conn */, const std::string& /* sender */, |
1063 | - const std::shared_ptr<GVariant>& /* params */) { |
1064 | - /* Nothing to do today */ |
1065 | - reg->impl->manager_->focusRequest(app, instance, [](bool response) { |
1066 | - /* NOTE: We have no clue what thread this is gonna be |
1067 | - executed on, but since we're just talking to the GDBus |
1068 | - thread it isn't an issue today. Be careful in changing |
1069 | - this code. */ |
1070 | - }); |
1071 | - }); |
1072 | - reg->impl->handle_managerSignalStarting = managerSignalHelper( |
1073 | - reg, "UnityStartingBroadcast", |
1074 | - [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
1075 | - const std::shared_ptr<Application::Instance>& instance, |
1076 | - const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
1077 | - const std::shared_ptr<GVariant>& params) { |
1078 | - |
1079 | - reg->impl->manager_->startingRequest(app, instance, [conn, sender, params](bool response) { |
1080 | - /* NOTE: We have no clue what thread this is gonna be |
1081 | - executed on, but since we're just talking to the GDBus |
1082 | - thread it isn't an issue today. Be careful in changing |
1083 | - this code. */ |
1084 | - if (response) |
1085 | - { |
1086 | - g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
1087 | - "/", /* path */ |
1088 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1089 | - "UnityStartingSignal", /* signal */ |
1090 | - params.get(), /* params, the same */ |
1091 | - nullptr); /* error */ |
1092 | - } |
1093 | - }); |
1094 | - }); |
1095 | - reg->impl->handle_managerSignalResume = managerSignalHelper( |
1096 | - reg, "UnityResumeRequest", |
1097 | - [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
1098 | - const std::shared_ptr<Application::Instance>& instance, |
1099 | - const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
1100 | - const std::shared_ptr<GVariant>& params) { |
1101 | - reg->impl->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) { |
1102 | - /* NOTE: We have no clue what thread this is gonna be |
1103 | - executed on, but since we're just talking to the GDBus |
1104 | - thread it isn't an issue today. Be careful in changing |
1105 | - this code. */ |
1106 | - if (response) |
1107 | - { |
1108 | - g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
1109 | - "/", /* path */ |
1110 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1111 | - "UnityResumeResponse", /* signal */ |
1112 | - params.get(), /* params, the same */ |
1113 | - nullptr); /* error */ |
1114 | - } |
1115 | - }); |
1116 | - }); |
1117 | - |
1118 | - return true; |
1119 | - })) |
1120 | - { |
1121 | - g_warning("Unable to install manager signals"); |
1122 | - } |
1123 | - }); |
1124 | -} |
1125 | - |
1126 | -/** Clear the manager pointer */ |
1127 | -void Registry::Impl::clearManager() |
1128 | -{ |
1129 | - g_debug("Clearing the manager"); |
1130 | - manager_.reset(); |
1131 | -} |
1132 | - |
1133 | /** App start watching, if we're registered for the signal we |
1134 | can't wait on it. We are making this static right now because |
1135 | we need it to go across the C and C++ APIs smoothly, and those |
1136 | @@ -513,340 +294,5 @@ |
1137 | return watchingAppStarting_; |
1138 | } |
1139 | |
1140 | -/** Regex to parse the JOB environment variable from Upstart */ |
1141 | -const std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"}; |
1142 | -/** Regex to parse the INSTANCE environment variable from Upstart */ |
1143 | -const std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"}; |
1144 | - |
1145 | -/** Core of most of the events that come from Upstart directly. Includes parsing of the |
1146 | - Upstart event environment and calling the appropriate signal with the right Application |
1147 | - object and eventually its instance */ |
1148 | -void Registry::Impl::upstartEventEmitted( |
1149 | - core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal, |
1150 | - const std::shared_ptr<GVariant>& params, |
1151 | - const std::shared_ptr<Registry>& reg) |
1152 | -{ |
1153 | - std::string jobname; |
1154 | - std::string sappid; |
1155 | - std::string instance; |
1156 | - |
1157 | - gchar* env = nullptr; |
1158 | - auto envs = g_variant_get_child_value(params.get(), 1); |
1159 | - GVariantIter iter; |
1160 | - g_variant_iter_init(&iter, envs); |
1161 | - |
1162 | - while (g_variant_iter_loop(&iter, "s", &env)) |
1163 | - { |
1164 | - std::smatch match; |
1165 | - std::string senv = env; |
1166 | - |
1167 | - if (std::regex_match(senv, match, jobenv_regex)) |
1168 | - { |
1169 | - jobname = match[1].str(); |
1170 | - } |
1171 | - else if (std::regex_match(senv, match, instanceenv_regex)) |
1172 | - { |
1173 | - sappid = match[1].str(); |
1174 | - instance = match[2].str(); |
1175 | - } |
1176 | - } |
1177 | - |
1178 | - g_variant_unref(envs); |
1179 | - |
1180 | - if (jobname.empty()) |
1181 | - { |
1182 | - return; |
1183 | - } |
1184 | - |
1185 | - g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str()); |
1186 | - |
1187 | - auto appid = AppID::find(reg, sappid); |
1188 | - auto app = Application::create(appid, reg); |
1189 | - |
1190 | - // TODO: Figure out creating instances |
1191 | - |
1192 | - signal(app, {}); |
1193 | -} |
1194 | - |
1195 | -/** Grab the signal object for application startup. If we're not already listing for |
1196 | - those signals this sets up a listener for them. */ |
1197 | -core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& |
1198 | - Registry::Impl::appStarted(const std::shared_ptr<Registry>& reg) |
1199 | -{ |
1200 | - std::call_once(flag_appStarted, [reg]() { |
1201 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1202 | - auto data = new upstartEventData{reg}; |
1203 | - |
1204 | - reg->impl->handle_appStarted = g_dbus_connection_signal_subscribe( |
1205 | - reg->impl->_dbus.get(), /* bus */ |
1206 | - nullptr, /* sender */ |
1207 | - DBUS_INTERFACE_UPSTART, /* interface */ |
1208 | - "EventEmitted", /* signal */ |
1209 | - DBUS_PATH_UPSTART, /* path */ |
1210 | - "started", /* arg0 */ |
1211 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1212 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1213 | - gpointer user_data) { |
1214 | - auto data = static_cast<upstartEventData*>(user_data); |
1215 | - auto reg = data->weakReg.lock(); |
1216 | - |
1217 | - if (!reg) |
1218 | - { |
1219 | - g_warning("Registry object invalid!"); |
1220 | - return; |
1221 | - } |
1222 | - |
1223 | - auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
1224 | - reg->impl->upstartEventEmitted(reg->impl->sig_appStarted, sparams, reg); |
1225 | - }, /* callback */ |
1226 | - data, /* user data */ |
1227 | - [](gpointer user_data) { |
1228 | - auto data = static_cast<upstartEventData*>(user_data); |
1229 | - delete data; |
1230 | - }); /* user data destroy */ |
1231 | - |
1232 | - return true; |
1233 | - }); |
1234 | - }); |
1235 | - |
1236 | - return sig_appStarted; |
1237 | -} |
1238 | - |
1239 | -/** Grab the signal object for application stopping. If we're not already listing for |
1240 | - those signals this sets up a listener for them. */ |
1241 | -core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& |
1242 | - Registry::Impl::appStopped(const std::shared_ptr<Registry>& reg) |
1243 | -{ |
1244 | - std::call_once(flag_appStopped, [reg]() { |
1245 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1246 | - auto data = new upstartEventData{reg}; |
1247 | - |
1248 | - reg->impl->handle_appStopped = g_dbus_connection_signal_subscribe( |
1249 | - reg->impl->_dbus.get(), /* bus */ |
1250 | - nullptr, /* sender */ |
1251 | - DBUS_INTERFACE_UPSTART, /* interface */ |
1252 | - "EventEmitted", /* signal */ |
1253 | - DBUS_PATH_UPSTART, /* path */ |
1254 | - "stopped", /* arg0 */ |
1255 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1256 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1257 | - gpointer user_data) { |
1258 | - auto data = static_cast<upstartEventData*>(user_data); |
1259 | - auto reg = data->weakReg.lock(); |
1260 | - |
1261 | - if (!reg) |
1262 | - { |
1263 | - g_warning("Registry object invalid!"); |
1264 | - return; |
1265 | - } |
1266 | - |
1267 | - auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
1268 | - reg->impl->upstartEventEmitted(reg->impl->sig_appStopped, sparams, reg); |
1269 | - }, /* callback */ |
1270 | - data, /* user data */ |
1271 | - [](gpointer user_data) { |
1272 | - auto data = static_cast<upstartEventData*>(user_data); |
1273 | - delete data; |
1274 | - }); /* user data destroy */ |
1275 | - |
1276 | - return true; |
1277 | - }); |
1278 | - }); |
1279 | - |
1280 | - return sig_appStopped; |
1281 | -} |
1282 | - |
1283 | -/** Grab the signal object for application failing. If we're not already listing for |
1284 | - those signals this sets up a listener for them. */ |
1285 | -core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>& |
1286 | - Registry::Impl::appFailed(const std::shared_ptr<Registry>& reg) |
1287 | -{ |
1288 | - std::call_once(flag_appFailed, [reg]() { |
1289 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1290 | - auto data = new upstartEventData{reg}; |
1291 | - |
1292 | - reg->impl->handle_appFailed = g_dbus_connection_signal_subscribe( |
1293 | - reg->impl->_dbus.get(), /* bus */ |
1294 | - nullptr, /* sender */ |
1295 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1296 | - "ApplicationFailed", /* signal */ |
1297 | - "/", /* path */ |
1298 | - nullptr, /* arg0 */ |
1299 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1300 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1301 | - gpointer user_data) { |
1302 | - auto data = static_cast<upstartEventData*>(user_data); |
1303 | - auto reg = data->weakReg.lock(); |
1304 | - |
1305 | - if (!reg) |
1306 | - { |
1307 | - g_warning("Registry object invalid!"); |
1308 | - return; |
1309 | - } |
1310 | - |
1311 | - const gchar* sappid = nullptr; |
1312 | - const gchar* typestr = nullptr; |
1313 | - |
1314 | - Registry::FailureType type = Registry::FailureType::CRASH; |
1315 | - g_variant_get(params, "(&s&s)", &sappid, &typestr); |
1316 | - |
1317 | - if (g_strcmp0("crash", typestr) == 0) |
1318 | - { |
1319 | - type = Registry::FailureType::CRASH; |
1320 | - } |
1321 | - else if (g_strcmp0("start-failure", typestr) == 0) |
1322 | - { |
1323 | - type = Registry::FailureType::START_FAILURE; |
1324 | - } |
1325 | - else |
1326 | - { |
1327 | - g_warning("Application failure type '%s' unknown, reporting as a crash", typestr); |
1328 | - } |
1329 | - |
1330 | - auto appid = AppID::find(reg, sappid); |
1331 | - auto app = Application::create(appid, reg); |
1332 | - |
1333 | - /* TODO: Instance issues */ |
1334 | - |
1335 | - reg->impl->sig_appFailed(app, {}, type); |
1336 | - }, /* callback */ |
1337 | - data, /* user data */ |
1338 | - [](gpointer user_data) { |
1339 | - auto data = static_cast<upstartEventData*>(user_data); |
1340 | - delete data; |
1341 | - }); /* user data destroy */ |
1342 | - |
1343 | - return true; |
1344 | - }); |
1345 | - }); |
1346 | - |
1347 | - return sig_appFailed; |
1348 | -} |
1349 | - |
1350 | -/** Core handler for pause and resume events. Includes turning the GVariant |
1351 | - pid list into a std::vector and getting the application object. */ |
1352 | -void Registry::Impl::pauseEventEmitted(core::Signal<const std::shared_ptr<Application>&, |
1353 | - const std::shared_ptr<Application::Instance>&, |
1354 | - const std::vector<pid_t>&>& signal, |
1355 | - const std::shared_ptr<GVariant>& params, |
1356 | - const std::shared_ptr<Registry>& reg) |
1357 | -{ |
1358 | - std::vector<pid_t> pids; |
1359 | - auto vappid = g_variant_get_child_value(params.get(), 0); |
1360 | - auto vpids = g_variant_get_child_value(params.get(), 1); |
1361 | - guint64 pid; |
1362 | - GVariantIter thispid; |
1363 | - g_variant_iter_init(&thispid, vpids); |
1364 | - |
1365 | - while (g_variant_iter_loop(&thispid, "t", &pid)) |
1366 | - { |
1367 | - pids.emplace_back(pid); |
1368 | - } |
1369 | - |
1370 | - auto cappid = g_variant_get_string(vappid, nullptr); |
1371 | - auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
1372 | - auto app = Application::create(appid, reg); |
1373 | - |
1374 | - /* TODO: Instance */ |
1375 | - signal(app, {}, pids); |
1376 | - |
1377 | - g_variant_unref(vappid); |
1378 | - g_variant_unref(vpids); |
1379 | - |
1380 | - return; |
1381 | -} |
1382 | - |
1383 | -/** Grab the signal object for application paused. If we're not already listing for |
1384 | - those signals this sets up a listener for them. */ |
1385 | -core::Signal<const std::shared_ptr<Application>&, |
1386 | - const std::shared_ptr<Application::Instance>&, |
1387 | - const std::vector<pid_t>&>& |
1388 | - Registry::Impl::appPaused(const std::shared_ptr<Registry>& reg) |
1389 | -{ |
1390 | - std::call_once(flag_appPaused, [&]() { |
1391 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1392 | - auto data = new upstartEventData{reg}; |
1393 | - |
1394 | - reg->impl->handle_appPaused = g_dbus_connection_signal_subscribe( |
1395 | - reg->impl->_dbus.get(), /* bus */ |
1396 | - nullptr, /* sender */ |
1397 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1398 | - "ApplicationPaused", /* signal */ |
1399 | - "/", /* path */ |
1400 | - nullptr, /* arg0 */ |
1401 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1402 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1403 | - gpointer user_data) { |
1404 | - auto data = static_cast<upstartEventData*>(user_data); |
1405 | - auto reg = data->weakReg.lock(); |
1406 | - |
1407 | - if (!reg) |
1408 | - { |
1409 | - g_warning("Registry object invalid!"); |
1410 | - return; |
1411 | - } |
1412 | - |
1413 | - auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
1414 | - reg->impl->pauseEventEmitted(reg->impl->sig_appPaused, sparams, reg); |
1415 | - }, /* callback */ |
1416 | - data, /* user data */ |
1417 | - [](gpointer user_data) { |
1418 | - auto data = static_cast<upstartEventData*>(user_data); |
1419 | - delete data; |
1420 | - }); /* user data destroy */ |
1421 | - |
1422 | - return true; |
1423 | - }); |
1424 | - }); |
1425 | - |
1426 | - return sig_appPaused; |
1427 | -} |
1428 | - |
1429 | -/** Grab the signal object for application resumed. If we're not already listing for |
1430 | - those signals this sets up a listener for them. */ |
1431 | -core::Signal<const std::shared_ptr<Application>&, |
1432 | - const std::shared_ptr<Application::Instance>&, |
1433 | - const std::vector<pid_t>&>& |
1434 | - Registry::Impl::appResumed(const std::shared_ptr<Registry>& reg) |
1435 | -{ |
1436 | - std::call_once(flag_appResumed, [&]() { |
1437 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1438 | - auto data = new upstartEventData{reg}; |
1439 | - |
1440 | - reg->impl->handle_appResumed = g_dbus_connection_signal_subscribe( |
1441 | - reg->impl->_dbus.get(), /* bus */ |
1442 | - nullptr, /* sender */ |
1443 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1444 | - "ApplicationResumed", /* signal */ |
1445 | - "/", /* path */ |
1446 | - nullptr, /* arg0 */ |
1447 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1448 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1449 | - gpointer user_data) { |
1450 | - auto data = static_cast<upstartEventData*>(user_data); |
1451 | - auto reg = data->weakReg.lock(); |
1452 | - |
1453 | - if (!reg) |
1454 | - { |
1455 | - g_warning("Registry object invalid!"); |
1456 | - return; |
1457 | - } |
1458 | - |
1459 | - auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
1460 | - reg->impl->pauseEventEmitted(reg->impl->sig_appResumed, sparams, reg); |
1461 | - }, /* callback */ |
1462 | - data, /* user data */ |
1463 | - [](gpointer user_data) { |
1464 | - auto data = static_cast<upstartEventData*>(user_data); |
1465 | - delete data; |
1466 | - }); /* user data destroy */ |
1467 | - |
1468 | - return true; |
1469 | - }); |
1470 | - }); |
1471 | - |
1472 | - return sig_appResumed; |
1473 | -} |
1474 | - |
1475 | } // namespace app_launch |
1476 | } // namespace ubuntu |
1477 | |
1478 | === modified file 'libubuntu-app-launch/registry-impl.h' |
1479 | --- libubuntu-app-launch/registry-impl.h 2017-01-19 03:25:37 +0000 |
1480 | +++ libubuntu-app-launch/registry-impl.h 2017-01-19 03:25:37 +0000 |
1481 | @@ -78,22 +78,6 @@ |
1482 | static std::string printJson(std::shared_ptr<JsonObject> jsonobj); |
1483 | static std::string printJson(std::shared_ptr<JsonNode> jsonnode); |
1484 | |
1485 | - /* Signals to discover what is happening to apps */ |
1486 | - core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& appStarted( |
1487 | - const std::shared_ptr<Registry>& reg); |
1488 | - core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& appStopped( |
1489 | - const std::shared_ptr<Registry>& reg); |
1490 | - core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, FailureType>& |
1491 | - appFailed(const std::shared_ptr<Registry>& reg); |
1492 | - core::Signal<const std::shared_ptr<Application>&, |
1493 | - const std::shared_ptr<Application::Instance>&, |
1494 | - const std::vector<pid_t>&>& |
1495 | - appPaused(const std::shared_ptr<Registry>& reg); |
1496 | - core::Signal<const std::shared_ptr<Application>&, |
1497 | - const std::shared_ptr<Application::Instance>&, |
1498 | - const std::vector<pid_t>&>& |
1499 | - appResumed(const std::shared_ptr<Registry>& reg); |
1500 | - |
1501 | /* Signal Hints */ |
1502 | /* NOTE: Static because we don't have registry instances in the C |
1503 | code right now. We want these to not be static in the future */ |
1504 | @@ -101,72 +85,11 @@ |
1505 | static bool isWatchingAppStarting(); |
1506 | |
1507 | private: |
1508 | - Registry* _registry; /**< The Registry that we're spawned from */ |
1509 | - std::shared_ptr<Registry::Manager> manager_; /**< Application manager if registered */ |
1510 | + Registry* _registry; /**< The Registry that we're spawned from */ |
1511 | |
1512 | std::shared_ptr<ClickDB> _clickDB; /**< Shared instance of the Click Database */ |
1513 | std::shared_ptr<ClickUser> _clickUser; /**< Click database filtered by the current user */ |
1514 | |
1515 | - /** Signal object for applications started */ |
1516 | - core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&> sig_appStarted; |
1517 | - /** Signal object for applications stopped */ |
1518 | - core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&> sig_appStopped; |
1519 | - /** Signal object for applications failed */ |
1520 | - core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, FailureType> |
1521 | - sig_appFailed; |
1522 | - /** Signal object for applications paused */ |
1523 | - core::Signal<const std::shared_ptr<Application>&, |
1524 | - const std::shared_ptr<Application::Instance>&, |
1525 | - const std::vector<pid_t>&> |
1526 | - sig_appPaused; |
1527 | - /** Signal object for applications resumed */ |
1528 | - core::Signal<const std::shared_ptr<Application>&, |
1529 | - const std::shared_ptr<Application::Instance>&, |
1530 | - const std::vector<pid_t>&> |
1531 | - sig_appResumed; |
1532 | - |
1533 | - guint handle_appStarted{0}; /**< GDBus signal watcher handle for app started signal */ |
1534 | - guint handle_appStopped{0}; /**< GDBus signal watcher handle for app stopped signal */ |
1535 | - guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */ |
1536 | - guint handle_appPaused{0}; /**< GDBus signal watcher handle for app paused signal */ |
1537 | - guint handle_appResumed{0}; /**< GDBus signal watcher handle for app resumed signal */ |
1538 | - guint handle_managerSignalFocus{0}; /**< GDBus signal watcher handle for app focused signal */ |
1539 | - guint handle_managerSignalResume{0}; /**< GDBus signal watcher handle for app resumed signal */ |
1540 | - guint handle_managerSignalStarting{0}; /**< GDBus signal watcher handle for app starting signal */ |
1541 | - |
1542 | - std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application |
1543 | - started */ |
1544 | - std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application |
1545 | - stopped */ |
1546 | - std::once_flag |
1547 | - flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */ |
1548 | - std::once_flag |
1549 | - flag_appPaused; /**< Variable to track to see if signal handlers are installed for application paused */ |
1550 | - std::once_flag flag_appResumed; /**< Variable to track to see if signal handlers are installed for application |
1551 | - resumed */ |
1552 | - std::once_flag flag_managerSignals; /**< Variable to track to see if signal handlers are installed for the manager |
1553 | - signals of focused, resumed and starting */ |
1554 | - |
1555 | - void upstartEventEmitted( |
1556 | - core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal, |
1557 | - const std::shared_ptr<GVariant>& params, |
1558 | - const std::shared_ptr<Registry>& reg); |
1559 | - void pauseEventEmitted(core::Signal<const std::shared_ptr<Application>&, |
1560 | - const std::shared_ptr<Application::Instance>&, |
1561 | - const std::vector<pid_t>&>& signal, |
1562 | - const std::shared_ptr<GVariant>& params, |
1563 | - const std::shared_ptr<Registry>& reg); |
1564 | - static std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> managerParams( |
1565 | - const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg); |
1566 | - static guint managerSignalHelper(const std::shared_ptr<Registry>& reg, |
1567 | - const std::string& signalname, |
1568 | - std::function<void(const std::shared_ptr<Registry>& reg, |
1569 | - const std::shared_ptr<Application>& app, |
1570 | - const std::shared_ptr<Application::Instance>& instance, |
1571 | - const std::shared_ptr<GDBusConnection>&, |
1572 | - const std::string&, |
1573 | - const std::shared_ptr<GVariant>&)> responsefunc); |
1574 | - |
1575 | void initClick(); |
1576 | |
1577 | /** Shared instance of the Zeitgeist Log */ |
1578 | |
1579 | === modified file 'libubuntu-app-launch/registry.cpp' |
1580 | --- libubuntu-app-launch/registry.cpp 2017-01-19 03:25:37 +0000 |
1581 | +++ libubuntu-app-launch/registry.cpp 2017-01-19 03:25:37 +0000 |
1582 | @@ -80,14 +80,29 @@ |
1583 | return list; |
1584 | } |
1585 | |
1586 | +/* Quick little helper to bundle up standard code */ |
1587 | +inline void setJobs(const std::shared_ptr<Registry>& registry) |
1588 | +{ |
1589 | + if (!registry->impl->jobs) |
1590 | + { |
1591 | + registry->impl->jobs = jobs::manager::Base::determineFactory(registry); |
1592 | + } |
1593 | +} |
1594 | + |
1595 | void Registry::setManager(const std::shared_ptr<Manager>& manager, const std::shared_ptr<Registry>& registry) |
1596 | { |
1597 | - Registry::Impl::setManager(manager, registry); |
1598 | + setJobs(registry); |
1599 | + registry->impl->jobs->setManager(manager); |
1600 | } |
1601 | |
1602 | void Registry::clearManager() |
1603 | { |
1604 | - impl->clearManager(); |
1605 | + if (!impl->jobs) |
1606 | + { |
1607 | + return; |
1608 | + } |
1609 | + |
1610 | + impl->jobs->clearManager(); |
1611 | } |
1612 | |
1613 | std::shared_ptr<Registry> defaultRegistry; |
1614 | @@ -109,19 +124,22 @@ |
1615 | core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Registry::appStarted( |
1616 | const std::shared_ptr<Registry>& reg) |
1617 | { |
1618 | - return reg->impl->appStarted(reg); |
1619 | + setJobs(reg); |
1620 | + return reg->impl->jobs->appStarted(); |
1621 | } |
1622 | |
1623 | core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Registry::appStopped( |
1624 | const std::shared_ptr<Registry>& reg) |
1625 | { |
1626 | - return reg->impl->appStopped(reg); |
1627 | + setJobs(reg); |
1628 | + return reg->impl->jobs->appStopped(); |
1629 | } |
1630 | |
1631 | core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>& |
1632 | Registry::appFailed(const std::shared_ptr<Registry>& reg) |
1633 | { |
1634 | - return reg->impl->appFailed(reg); |
1635 | + setJobs(reg); |
1636 | + return reg->impl->jobs->appFailed(); |
1637 | } |
1638 | |
1639 | core::Signal<const std::shared_ptr<Application>&, |
1640 | @@ -129,7 +147,8 @@ |
1641 | const std::vector<pid_t>&>& |
1642 | Registry::appPaused(const std::shared_ptr<Registry>& reg) |
1643 | { |
1644 | - return reg->impl->appPaused(reg); |
1645 | + setJobs(reg); |
1646 | + return reg->impl->jobs->appPaused(); |
1647 | } |
1648 | |
1649 | core::Signal<const std::shared_ptr<Application>&, |
1650 | @@ -137,7 +156,8 @@ |
1651 | const std::vector<pid_t>&>& |
1652 | Registry::appResumed(const std::shared_ptr<Registry>& reg) |
1653 | { |
1654 | - return reg->impl->appResumed(reg); |
1655 | + setJobs(reg); |
1656 | + return reg->impl->jobs->appResumed(); |
1657 | } |
1658 | |
1659 | } // namespace app_launch |
PASSED: Continuous integration, rev:278 /jenkins. canonical. com/unity- api-1/job/ lp-ubuntu- app-launch- ci/136/ /jenkins. canonical. com/unity- api-1/job/ build/1274 /jenkins. canonical. com/unity- api-1/job/ build-0- fetch/1281 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 1061 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 1061/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= zesty/1061 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= zesty/1061/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 1061 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 1061/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= zesty/1061 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= zesty/1061/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 1061 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 1061/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= zesty/1061 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= zesty/1061/ artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/unity- api-1/job/ lp-ubuntu- app-launch- ci/136/ rebuild
https:/