~townsend/ubuntu-app-launch/remove-xmir-helpers

« back to all changes in this revision

Viewing changes to libubuntu-app-launch/jobs-base.cpp

  • Committer: Chris Townsend
  • Date: 2017-03-24 13:06:32 UTC
  • mfrom: (269.1.38 ubuntu-app-launch)
  • Revision ID: christopher.townsend@canonical.com-20170324130632-n52ashmczuy0vy4y
MergeĀ lp:ubuntu-app-launch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
#include <cerrno>
22
22
#include <cstring>
23
23
#include <numeric>
 
24
#include <unity/util/GObjectMemory.h>
 
25
#include <unity/util/GlibMemory.h>
 
26
#include <unity/util/ResourcePtr.h>
24
27
 
25
28
#include "application-impl-base.h"
 
29
#include "helper-impl.h"
26
30
#include "jobs-base.h"
27
31
#include "jobs-systemd.h"
28
 
#include "jobs-upstart.h"
29
32
#include "registry-impl.h"
 
33
#include "string-util.h"
 
34
 
 
35
using namespace unity::util;
30
36
 
31
37
namespace ubuntu
32
38
{
39
45
 
40
46
Base::Base(const std::shared_ptr<Registry>& registry)
41
47
    : registry_(registry)
42
 
    , allJobs_{"application-click", "application-legacy", "application-snap"}
 
48
    , allApplicationJobs_{"application-legacy", "application-snap"}
43
49
    , dbus_(registry->impl->_dbus)
44
50
{
45
51
}
46
52
 
47
53
Base::~Base()
48
54
{
49
 
    auto dohandle = [&](guint& handle) {
50
 
        if (handle != 0)
51
 
        {
52
 
            g_dbus_connection_signal_unsubscribe(dbus_.get(), handle);
53
 
            handle = 0;
54
 
        }
55
 
    };
56
 
 
57
 
    dohandle(handle_managerSignalFocus);
58
 
    dohandle(handle_managerSignalResume);
59
 
    dohandle(handle_managerSignalStarting);
60
 
    dohandle(handle_appPaused);
61
 
    dohandle(handle_appResumed);
62
55
}
63
56
 
 
57
/** Should determine which jobs backend to use, but we only have
 
58
    one right now. */
64
59
std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry)
65
60
{
66
 
    /* Checking to see if we have a user bus, that is only started
67
 
       by systemd so we're in good shape if we have one. We're using
68
 
       the path instead of the RUNTIME variable because we want to work
69
 
       around the case of being relocated by the snappy environment */
70
 
    if (g_file_test(SystemD::userBusPath().c_str(), G_FILE_TEST_EXISTS))
71
 
    {
72
 
        g_debug("Building a systemd jobs manager");
73
 
        return std::make_shared<jobs::manager::SystemD>(registry);
74
 
    }
75
 
    else
76
 
    {
77
 
        g_debug("Building an Upstart jobs manager");
78
 
        return std::make_shared<jobs::manager::Upstart>(registry);
79
 
    }
80
 
}
81
 
 
82
 
const std::set<std::string>& Base::getAllJobs() const
83
 
{
84
 
    return allJobs_;
 
61
    g_debug("Building a systemd jobs manager");
 
62
    return std::make_shared<jobs::manager::SystemD>(registry);
 
63
}
 
64
 
 
65
const std::list<std::string>& Base::getAllApplicationJobs() const
 
66
{
 
67
    return allApplicationJobs_;
 
68
}
 
69
 
 
70
core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Base::appStarted()
 
71
{
 
72
    std::call_once(flag_appStarted, [this]() {
 
73
        jobStarted().connect([this](const std::string& job, const std::string& appid, const std::string& instanceid) {
 
74
            if (std::find(allApplicationJobs_.begin(), allApplicationJobs_.end(), job) == allApplicationJobs_.end())
 
75
            {
 
76
                /* Not an application, different signal */
 
77
                return;
 
78
            }
 
79
 
 
80
            try
 
81
            {
 
82
                auto reg = registry_.lock();
 
83
 
 
84
                auto appId = AppID::find(reg, appid);
 
85
                auto app = Application::create(appId, reg);
 
86
                auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
 
87
 
 
88
                sig_appStarted(app, inst);
 
89
            }
 
90
            catch (std::runtime_error& e)
 
91
            {
 
92
                g_warning("Error in appStarted signal from job: %s", e.what());
 
93
            }
 
94
        });
 
95
    });
 
96
 
 
97
    return sig_appStarted;
 
98
}
 
99
 
 
100
core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Base::appStopped()
 
101
{
 
102
    std::call_once(flag_appStopped, [this]() {
 
103
        jobStopped().connect([this](const std::string& job, const std::string& appid, const std::string& instanceid) {
 
104
            if (std::find(allApplicationJobs_.begin(), allApplicationJobs_.end(), job) == allApplicationJobs_.end())
 
105
            {
 
106
                /* Not an application, different signal */
 
107
                return;
 
108
            }
 
109
 
 
110
            try
 
111
            {
 
112
                auto reg = registry_.lock();
 
113
 
 
114
                auto appId = AppID::find(reg, appid);
 
115
                auto app = Application::create(appId, reg);
 
116
                auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
 
117
 
 
118
                sig_appStopped(app, inst);
 
119
            }
 
120
            catch (std::runtime_error& e)
 
121
            {
 
122
                g_warning("Error in appStopped signal from job: %s", e.what());
 
123
            }
 
124
        });
 
125
    });
 
126
 
 
127
    return sig_appStopped;
 
128
}
 
129
 
 
130
core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>&
 
131
    Base::appFailed()
 
132
{
 
133
    std::call_once(flag_appFailed, [this]() {
 
134
        jobFailed().connect([this](const std::string& job, const std::string& appid, const std::string& instanceid,
 
135
                                   Registry::FailureType reason) {
 
136
            if (std::find(allApplicationJobs_.begin(), allApplicationJobs_.end(), job) == allApplicationJobs_.end())
 
137
            {
 
138
                /* Not an application, different signal */
 
139
                return;
 
140
            }
 
141
 
 
142
            try
 
143
            {
 
144
                auto reg = registry_.lock();
 
145
 
 
146
                auto appId = AppID::find(reg, appid);
 
147
                auto app = Application::create(appId, reg);
 
148
                auto inst = std::dynamic_pointer_cast<app_impls::Base>(app)->findInstance(instanceid);
 
149
 
 
150
                sig_appFailed(app, inst, reason);
 
151
            }
 
152
            catch (std::runtime_error& e)
 
153
            {
 
154
                g_warning("Error in appFailed signal from job: %s", e.what());
 
155
            }
 
156
        });
 
157
    });
 
158
 
 
159
    return sig_appFailed;
85
160
}
86
161
 
87
162
/** Structure to track the data needed for upstart events. This cleans
103
178
                             const std::shared_ptr<Registry>& reg)
104
179
{
105
180
    std::vector<pid_t> pids;
106
 
    GVariant* vappid = g_variant_get_child_value(params.get(), 0);
107
 
    GVariant* vinstid = g_variant_get_child_value(params.get(), 1);
108
 
    GVariant* vpids = g_variant_get_child_value(params.get(), 2);
 
181
    auto vappid = unique_glib(g_variant_get_child_value(params.get(), 0));
 
182
    auto vinstid = unique_glib(g_variant_get_child_value(params.get(), 1));
 
183
    auto vpids = unique_glib(g_variant_get_child_value(params.get(), 2));
109
184
    guint64 pid;
110
185
    GVariantIter thispid;
111
 
    g_variant_iter_init(&thispid, vpids);
 
186
    g_variant_iter_init(&thispid, vpids.get());
112
187
 
113
188
    while (g_variant_iter_loop(&thispid, "t", &pid))
114
189
    {
115
190
        pids.emplace_back(pid);
116
191
    }
117
192
 
118
 
    auto cappid = g_variant_get_string(vappid, NULL);
119
 
    auto cinstid = g_variant_get_string(vinstid, NULL);
 
193
    auto cappid = g_variant_get_string(vappid.get(), NULL);
 
194
    auto cinstid = g_variant_get_string(vinstid.get(), NULL);
120
195
 
121
196
    auto appid = ubuntu::app_launch::AppID::find(reg, cappid);
122
197
    auto app = Application::create(appid, reg);
124
199
 
125
200
    signal(app, inst, pids);
126
201
 
127
 
    g_variant_unref(vappid);
128
 
    g_variant_unref(vinstid);
129
 
    g_variant_unref(vpids);
130
 
 
131
202
    return;
132
203
}
133
204
 
144
215
        reg->impl->thread.executeOnThread<bool>([this, reg]() {
145
216
            upstartEventData* data = new upstartEventData{reg};
146
217
 
147
 
            handle_appPaused = g_dbus_connection_signal_subscribe(
148
 
                reg->impl->_dbus.get(),          /* bus */
149
 
                nullptr,                         /* sender */
150
 
                "com.canonical.UbuntuAppLaunch", /* interface */
151
 
                "ApplicationPaused",             /* signal */
152
 
                "/",                             /* path */
153
 
                nullptr,                         /* arg0 */
154
 
                G_DBUS_SIGNAL_FLAGS_NONE,
155
 
                [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
156
 
                   gpointer user_data) -> void {
157
 
                    auto data = reinterpret_cast<upstartEventData*>(user_data);
158
 
                    auto reg = data->weakReg.lock();
159
 
 
160
 
                    if (!reg)
161
 
                    {
162
 
                        g_warning("Registry object invalid!");
163
 
                        return;
164
 
                    }
165
 
 
166
 
                    auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
167
 
                    auto manager = std::dynamic_pointer_cast<Base>(reg->impl->jobs);
168
 
                    manager->pauseEventEmitted(manager->sig_appPaused, sparams, reg);
169
 
                },    /* callback */
170
 
                data, /* user data */
171
 
                [](gpointer user_data) {
172
 
                    auto data = reinterpret_cast<upstartEventData*>(user_data);
173
 
                    delete data;
174
 
                }); /* user data destroy */
 
218
            handle_appPaused = managedDBusSignalConnection(
 
219
                g_dbus_connection_signal_subscribe(reg->impl->_dbus.get(),          /* bus */
 
220
                                                   nullptr,                         /* sender */
 
221
                                                   "com.canonical.UbuntuAppLaunch", /* interface */
 
222
                                                   "ApplicationPaused",             /* signal */
 
223
                                                   "/",                             /* path */
 
224
                                                   nullptr,                         /* arg0 */
 
225
                                                   G_DBUS_SIGNAL_FLAGS_NONE,
 
226
                                                   [](GDBusConnection*, const gchar*, const gchar*, const gchar*,
 
227
                                                      const gchar*, GVariant* params, gpointer user_data) -> void {
 
228
                                                       auto data = reinterpret_cast<upstartEventData*>(user_data);
 
229
                                                       auto reg = data->weakReg.lock();
 
230
 
 
231
                                                       if (!reg)
 
232
                                                       {
 
233
                                                           g_warning("Registry object invalid!");
 
234
                                                           return;
 
235
                                                       }
 
236
 
 
237
                                                       auto sparams = share_glib(g_variant_ref(params));
 
238
                                                       auto manager = std::dynamic_pointer_cast<Base>(reg->impl->jobs);
 
239
                                                       manager->pauseEventEmitted(manager->sig_appPaused, sparams, reg);
 
240
                                                   },    /* callback */
 
241
                                                   data, /* user data */
 
242
                                                   [](gpointer user_data) {
 
243
                                                       auto data = reinterpret_cast<upstartEventData*>(user_data);
 
244
                                                       delete data;
 
245
                                                   }), /* user data destroy */
 
246
                reg->impl->_dbus);
175
247
 
176
248
            return true;
177
249
        });
193
265
        reg->impl->thread.executeOnThread<bool>([this, reg]() {
194
266
            upstartEventData* data = new upstartEventData{reg};
195
267
 
196
 
            handle_appResumed = g_dbus_connection_signal_subscribe(
197
 
                reg->impl->_dbus.get(),          /* bus */
198
 
                nullptr,                         /* sender */
199
 
                "com.canonical.UbuntuAppLaunch", /* interface */
200
 
                "ApplicationResumed",            /* signal */
201
 
                "/",                             /* path */
202
 
                nullptr,                         /* arg0 */
203
 
                G_DBUS_SIGNAL_FLAGS_NONE,
204
 
                [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
205
 
                   gpointer user_data) -> void {
206
 
                    auto data = reinterpret_cast<upstartEventData*>(user_data);
207
 
                    auto reg = data->weakReg.lock();
208
 
 
209
 
                    if (!reg)
210
 
                    {
211
 
                        g_warning("Registry object invalid!");
212
 
                        return;
213
 
                    }
214
 
 
215
 
                    auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
216
 
                    auto manager = std::dynamic_pointer_cast<Base>(reg->impl->jobs);
217
 
                    manager->pauseEventEmitted(manager->sig_appResumed, sparams, reg);
218
 
                },    /* callback */
219
 
                data, /* user data */
220
 
                [](gpointer user_data) {
221
 
                    auto data = reinterpret_cast<upstartEventData*>(user_data);
222
 
                    delete data;
223
 
                }); /* user data destroy */
 
268
            handle_appResumed = managedDBusSignalConnection(
 
269
                g_dbus_connection_signal_subscribe(reg->impl->_dbus.get(),          /* bus */
 
270
                                                   nullptr,                         /* sender */
 
271
                                                   "com.canonical.UbuntuAppLaunch", /* interface */
 
272
                                                   "ApplicationResumed",            /* signal */
 
273
                                                   "/",                             /* path */
 
274
                                                   nullptr,                         /* arg0 */
 
275
                                                   G_DBUS_SIGNAL_FLAGS_NONE,
 
276
                                                   [](GDBusConnection*, const gchar*, const gchar*, const gchar*,
 
277
                                                      const gchar*, GVariant* params, gpointer user_data) -> void {
 
278
                                                       auto data = reinterpret_cast<upstartEventData*>(user_data);
 
279
                                                       auto reg = data->weakReg.lock();
 
280
 
 
281
                                                       if (!reg)
 
282
                                                       {
 
283
                                                           g_warning("Registry object invalid!");
 
284
                                                           return;
 
285
                                                       }
 
286
 
 
287
                                                       auto sparams = share_glib(g_variant_ref(params));
 
288
                                                       auto manager = std::dynamic_pointer_cast<Base>(reg->impl->jobs);
 
289
                                                       manager->pauseEventEmitted(manager->sig_appResumed, sparams,
 
290
                                                                                  reg);
 
291
                                                   },    /* callback */
 
292
                                                   data, /* user data */
 
293
                                                   [](gpointer user_data) {
 
294
                                                       auto data = reinterpret_cast<upstartEventData*>(user_data);
 
295
                                                       delete data;
 
296
                                                   }), /* user data destroy */
 
297
                reg->impl->_dbus);
224
298
 
225
299
            return true;
226
300
        });
229
303
    return sig_appResumed;
230
304
}
231
305
 
 
306
core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& Base::helperStarted(
 
307
    Helper::Type type)
 
308
{
 
309
    try
 
310
    {
 
311
        return *sig_helpersStarted.at(type.value());
 
312
    }
 
313
    catch (std::out_of_range& e)
 
314
    {
 
315
        jobStarted().connect(
 
316
            [this, type](const std::string& job, const std::string& appid, const std::string& instanceid) {
 
317
                if (job != type.value())
 
318
                {
 
319
                    return;
 
320
                }
 
321
 
 
322
                try
 
323
                {
 
324
                    auto reg = registry_.lock();
 
325
 
 
326
                    auto appId = ubuntu::app_launch::AppID::parse(appid);
 
327
                    auto helper = Helper::create(type, appId, reg);
 
328
                    auto inst = std::dynamic_pointer_cast<helper_impls::Base>(helper)->existingInstance(instanceid);
 
329
 
 
330
                    (*sig_helpersStarted.at(type.value()))(helper, inst);
 
331
                }
 
332
                catch (...)
 
333
                {
 
334
                    g_warning("Unable to emit signal for helper type: %s", type.value().c_str());
 
335
                }
 
336
            });
 
337
 
 
338
        sig_helpersStarted.emplace(
 
339
            type.value(),
 
340
            std::make_shared<core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>>());
 
341
    }
 
342
 
 
343
    return *sig_helpersStarted.at(type.value());
 
344
}
 
345
 
 
346
core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>& Base::helperStopped(
 
347
    Helper::Type type)
 
348
{
 
349
    try
 
350
    {
 
351
        return *sig_helpersStopped.at(type.value());
 
352
    }
 
353
    catch (std::out_of_range& e)
 
354
    {
 
355
        jobStopped().connect(
 
356
            [this, type](const std::string& job, const std::string& appid, const std::string& instanceid) {
 
357
                if (job != type.value())
 
358
                {
 
359
                    return;
 
360
                }
 
361
 
 
362
                try
 
363
                {
 
364
                    auto reg = registry_.lock();
 
365
 
 
366
                    auto appId = ubuntu::app_launch::AppID::parse(appid);
 
367
                    auto helper = Helper::create(type, appId, reg);
 
368
                    auto inst = std::dynamic_pointer_cast<helper_impls::Base>(helper)->existingInstance(instanceid);
 
369
 
 
370
                    (*sig_helpersStopped.at(type.value()))(helper, inst);
 
371
                }
 
372
                catch (...)
 
373
                {
 
374
                    g_warning("Unable to emit signal for helper type: %s", type.value().c_str());
 
375
                }
 
376
            });
 
377
 
 
378
        sig_helpersStopped.emplace(
 
379
            type.value(),
 
380
            std::make_shared<core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&>>());
 
381
    }
 
382
 
 
383
    return *sig_helpersStopped.at(type.value());
 
384
}
 
385
 
 
386
core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&, Registry::FailureType>&
 
387
    Base::helperFailed(Helper::Type type)
 
388
{
 
389
    try
 
390
    {
 
391
        return *sig_helpersFailed.at(type.value());
 
392
    }
 
393
    catch (std::out_of_range& e)
 
394
    {
 
395
        jobFailed().connect([this, type](const std::string& job, const std::string& appid,
 
396
                                         const std::string& instanceid, Registry::FailureType reason) {
 
397
            if (job != type.value())
 
398
            {
 
399
                return;
 
400
            }
 
401
 
 
402
            try
 
403
            {
 
404
                auto reg = registry_.lock();
 
405
 
 
406
                auto appId = ubuntu::app_launch::AppID::parse(appid);
 
407
                auto helper = Helper::create(type, appId, reg);
 
408
                auto inst = std::dynamic_pointer_cast<helper_impls::Base>(helper)->existingInstance(instanceid);
 
409
 
 
410
                (*sig_helpersFailed.at(type.value()))(helper, inst, reason);
 
411
            }
 
412
            catch (...)
 
413
            {
 
414
                g_warning("Unable to emit signal for helper type: %s", type.value().c_str());
 
415
            }
 
416
        });
 
417
 
 
418
        sig_helpersFailed.emplace(
 
419
            type.value(),
 
420
            std::make_shared<core::Signal<const std::shared_ptr<Helper>&, const std::shared_ptr<Helper::Instance>&,
 
421
                                          Registry::FailureType>>());
 
422
    }
 
423
 
 
424
    return *sig_helpersFailed.at(type.value());
 
425
}
 
426
 
232
427
/** Take the GVariant of parameters and turn them into an application and
233
428
    and instance. Easier to read in the smaller function */
234
429
std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Base::managerParams(
305
500
                return;
306
501
            }
307
502
 
308
 
            auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
309
 
            auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)),
310
 
                                                         [](GDBusConnection* con) { g_clear_object(&con); });
311
 
            std::string sender = csender;
312
 
            std::shared_ptr<Application> app;
313
 
            std::shared_ptr<Application::Instance> instance;
314
 
 
315
 
            std::tie(app, instance) = managerParams(vparams, reg);
316
 
 
317
 
            data->func(reg, app, instance, conn, sender, vparams);
 
503
            try
 
504
            {
 
505
                auto vparams = share_glib(g_variant_ref(params));
 
506
                auto conn = share_gobject(G_DBUS_CONNECTION(g_object_ref(cconn)));
 
507
                std::string sender = csender;
 
508
                std::shared_ptr<Application> app;
 
509
                std::shared_ptr<Application::Instance> instance;
 
510
 
 
511
                std::tie(app, instance) = managerParams(vparams, reg);
 
512
 
 
513
                data->func(reg, app, instance, conn, sender, vparams);
 
514
            }
 
515
            catch (std::runtime_error& e)
 
516
            {
 
517
                g_warning("Unable to call signal handler for manager signal: %s", e.what());
 
518
            }
318
519
        },
319
520
        focusdata,
320
521
        [](gpointer user_data) {
348
549
        }
349
550
 
350
551
        if (!reg->impl->thread.executeOnThread<bool>([this, reg]() {
351
 
                handle_managerSignalFocus = managerSignalHelper(
352
 
                    reg, "UnityFocusRequest",
353
 
                    [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
354
 
                       const std::shared_ptr<Application::Instance>& instance,
355
 
                       const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
356
 
                       const std::shared_ptr<GVariant>& params) {
357
 
                        /* Nothing to do today */
358
 
                        std::dynamic_pointer_cast<Base>(reg->impl->jobs)
359
 
                            ->manager_->focusRequest(app, instance, [](bool response) {
360
 
                                /* NOTE: We have no clue what thread this is gonna be
361
 
                                   executed on, but since we're just talking to the GDBus
362
 
                                   thread it isn't an issue today. Be careful in changing
363
 
                                   this code. */
364
 
                            });
365
 
                    });
366
 
                handle_managerSignalStarting = managerSignalHelper(
367
 
                    reg, "UnityStartingBroadcast",
368
 
                    [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
369
 
                       const std::shared_ptr<Application::Instance>& instance,
370
 
                       const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
371
 
                       const std::shared_ptr<GVariant>& params) {
 
552
                handle_managerSignalFocus = managedDBusSignalConnection(
 
553
                    managerSignalHelper(
 
554
                        reg, "UnityFocusRequest",
 
555
                        [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
 
556
                           const std::shared_ptr<Application::Instance>& instance,
 
557
                           const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
 
558
                           const std::shared_ptr<GVariant>& params) {
 
559
                            /* Nothing to do today */
 
560
                            std::dynamic_pointer_cast<Base>(reg->impl->jobs)
 
561
                                ->manager_->focusRequest(app, instance, [](bool response) {
 
562
                                    /* NOTE: We have no clue what thread this is gonna be
 
563
                                       executed on, but since we're just talking to the GDBus
 
564
                                       thread it isn't an issue today. Be careful in changing
 
565
                                       this code. */
 
566
                                });
 
567
                        }),
 
568
                    reg->impl->_dbus);
 
569
                handle_managerSignalStarting = managedDBusSignalConnection(
 
570
                    managerSignalHelper(
 
571
                        reg, "UnityStartingBroadcast",
 
572
                        [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
 
573
                           const std::shared_ptr<Application::Instance>& instance,
 
574
                           const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
 
575
                           const std::shared_ptr<GVariant>& params) {
372
576
 
373
 
                        std::dynamic_pointer_cast<Base>(reg->impl->jobs)
374
 
                            ->manager_->startingRequest(app, instance, [conn, sender, params](bool response) {
375
 
                                /* NOTE: We have no clue what thread this is gonna be
376
 
                                   executed on, but since we're just talking to the GDBus
377
 
                                   thread it isn't an issue today. Be careful in changing
378
 
                                   this code. */
379
 
                                if (response)
380
 
                                {
381
 
                                    g_dbus_connection_emit_signal(conn.get(), sender.c_str(),      /* destination */
382
 
                                                                  "/",                             /* path */
383
 
                                                                  "com.canonical.UbuntuAppLaunch", /* interface */
384
 
                                                                  "UnityStartingSignal",           /* signal */
385
 
                                                                  params.get(), /* params, the same */
386
 
                                                                  nullptr);     /* error */
387
 
                                }
388
 
                            });
389
 
                    });
390
 
                handle_managerSignalResume = managerSignalHelper(
391
 
                    reg, "UnityResumeRequest",
392
 
                    [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
393
 
                       const std::shared_ptr<Application::Instance>& instance,
394
 
                       const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
395
 
                       const std::shared_ptr<GVariant>& params) {
396
 
                        std::dynamic_pointer_cast<Base>(reg->impl->jobs)
397
 
                            ->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) {
398
 
                                /* NOTE: We have no clue what thread this is gonna be
399
 
                                   executed on, but since we're just talking to the GDBus
400
 
                                   thread it isn't an issue today. Be careful in changing
401
 
                                   this code. */
402
 
                                if (response)
403
 
                                {
404
 
                                    g_dbus_connection_emit_signal(conn.get(), sender.c_str(),      /* destination */
405
 
                                                                  "/",                             /* path */
406
 
                                                                  "com.canonical.UbuntuAppLaunch", /* interface */
407
 
                                                                  "UnityResumeResponse",           /* signal */
408
 
                                                                  params.get(), /* params, the same */
409
 
                                                                  nullptr);     /* error */
410
 
                                }
411
 
                            });
412
 
                    });
 
577
                            std::dynamic_pointer_cast<Base>(reg->impl->jobs)
 
578
                                ->manager_->startingRequest(app, instance, [conn, sender, params](bool response) {
 
579
                                    /* NOTE: We have no clue what thread this is gonna be
 
580
                                       executed on, but since we're just talking to the GDBus
 
581
                                       thread it isn't an issue today. Be careful in changing
 
582
                                       this code. */
 
583
                                    if (response)
 
584
                                    {
 
585
                                        g_dbus_connection_emit_signal(conn.get(), sender.c_str(),      /* destination */
 
586
                                                                      "/",                             /* path */
 
587
                                                                      "com.canonical.UbuntuAppLaunch", /* interface */
 
588
                                                                      "UnityStartingSignal",           /* signal */
 
589
                                                                      params.get(), /* params, the same */
 
590
                                                                      nullptr);     /* error */
 
591
                                    }
 
592
                                });
 
593
                        }),
 
594
                    reg->impl->_dbus);
 
595
                handle_managerSignalResume = managedDBusSignalConnection(
 
596
                    managerSignalHelper(
 
597
                        reg, "UnityResumeRequest",
 
598
                        [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
 
599
                           const std::shared_ptr<Application::Instance>& instance,
 
600
                           const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
 
601
                           const std::shared_ptr<GVariant>& params) {
 
602
                            std::dynamic_pointer_cast<Base>(reg->impl->jobs)
 
603
                                ->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) {
 
604
                                    /* NOTE: We have no clue what thread this is gonna be
 
605
                                       executed on, but since we're just talking to the GDBus
 
606
                                       thread it isn't an issue today. Be careful in changing
 
607
                                       this code. */
 
608
                                    if (response)
 
609
                                    {
 
610
                                        g_dbus_connection_emit_signal(conn.get(), sender.c_str(),      /* destination */
 
611
                                                                      "/",                             /* path */
 
612
                                                                      "com.canonical.UbuntuAppLaunch", /* interface */
 
613
                                                                      "UnityResumeResponse",           /* signal */
 
614
                                                                      params.get(), /* params, the same */
 
615
                                                                      nullptr);     /* error */
 
616
                                    }
 
617
                                });
 
618
                        }),
 
619
                    reg->impl->_dbus);
413
620
 
414
621
                return true;
415
622
            }))
426
633
    manager_.reset();
427
634
}
428
635
 
 
636
/** Get application objects for all of the applications based
 
637
    on the appids associated with the application jobs */
 
638
std::list<std::shared_ptr<Application>> Base::runningApps()
 
639
{
 
640
    auto registry = registry_.lock();
 
641
 
 
642
    if (!registry)
 
643
    {
 
644
        g_warning("Unable to list apps without a registry");
 
645
        return {};
 
646
    }
 
647
 
 
648
    auto appids = runningAppIds(allApplicationJobs_);
 
649
 
 
650
    std::list<std::shared_ptr<Application>> apps;
 
651
    for (const auto& appid : appids)
 
652
    {
 
653
        auto id = AppID::find(registry, appid);
 
654
        if (id.empty())
 
655
        {
 
656
            g_debug("Unable to handle AppID: %s", appid.c_str());
 
657
            continue;
 
658
        }
 
659
 
 
660
        try
 
661
        {
 
662
            apps.emplace_back(Application::create(id, registry));
 
663
        }
 
664
        catch (std::runtime_error& e)
 
665
        {
 
666
            g_debug("Error adding appid '%s' to running apps list: %s", appid.c_str(), e.what());
 
667
        }
 
668
    }
 
669
 
 
670
    return apps;
 
671
}
 
672
 
 
673
/** Get application objects for all of the applications based
 
674
    on the appids associated with the application jobs */
 
675
std::list<std::shared_ptr<Helper>> Base::runningHelpers(const Helper::Type& type)
 
676
{
 
677
    auto registry = registry_.lock();
 
678
 
 
679
    if (!registry)
 
680
    {
 
681
        g_warning("Unable to list helpers without a registry");
 
682
        return {};
 
683
    }
 
684
 
 
685
    auto appids = runningAppIds({type.value()});
 
686
 
 
687
    std::list<std::shared_ptr<Helper>> helpers;
 
688
    for (const auto& appid : appids)
 
689
    {
 
690
        auto id = AppID::parse(appid);
 
691
        if (id.empty())
 
692
        {
 
693
            g_debug("Unable to handle AppID: %s", appid.c_str());
 
694
            continue;
 
695
        }
 
696
 
 
697
        helpers.emplace_back(Helper::create(type, id, registry));
 
698
    }
 
699
 
 
700
    return helpers;
 
701
}
 
702
 
429
703
}  // namespace manager
430
704
 
431
705
namespace instance
567
841
                         const std::vector<pid_t>& pids,
568
842
                         const std::string& signal)
569
843
{
570
 
    auto vpids = std::shared_ptr<GVariant>(
571
 
        [pids]() {
572
 
            GVariant* pidarray = nullptr;
573
 
 
574
 
            if (pids.empty())
575
 
            {
576
 
                pidarray = g_variant_new_array(G_VARIANT_TYPE_UINT64, nullptr, 0);
577
 
                g_variant_ref_sink(pidarray);
578
 
                return pidarray;
579
 
            }
580
 
 
581
 
            GVariantBuilder builder;
582
 
            g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
583
 
            for (auto pid : pids)
584
 
            {
585
 
                g_variant_builder_add_value(&builder, g_variant_new_uint64(pid));
586
 
            }
587
 
 
588
 
            pidarray = g_variant_builder_end(&builder);
589
 
            g_variant_ref_sink(pidarray);
590
 
            return pidarray;
591
 
        }(),
592
 
        [](GVariant* var) { g_variant_unref(var); });
 
844
    GVariantUPtr vpids;
 
845
 
 
846
    if (pids.empty())
 
847
    {
 
848
        vpids = unique_glib(g_variant_ref_sink(g_variant_new_array(G_VARIANT_TYPE_UINT64, nullptr, 0)));
 
849
    }
 
850
    else
 
851
    {
 
852
        GVariantBuilder builder;
 
853
        g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
 
854
 
 
855
        for (auto pid : pids)
 
856
        {
 
857
            g_variant_builder_add_value(&builder, g_variant_new_uint64(pid));
 
858
        }
 
859
 
 
860
        vpids = unique_glib(g_variant_ref_sink(g_variant_builder_end(&builder)));
 
861
    }
593
862
 
594
863
    GVariantBuilder params;
595
864
    g_variant_builder_init(&params, G_VARIANT_TYPE_TUPLE);
649
918
 
650
919
    if (error != nullptr)
651
920
    {
652
 
        auto serror = std::shared_ptr<GError>(error, g_error_free);
 
921
        auto serror = unique_glib(error);
 
922
        error = nullptr;
653
923
        throw std::runtime_error("Unable to access OOM value for '" + std::string(appId_) + "' primary PID '" +
654
924
                                 std::to_string(pid) + "' because: " + serror->message);
655
925
    }
693
963
            procpath = envvar;
694
964
    }
695
965
 
696
 
    gchar* gpath = g_build_filename(procpath.c_str(), std::to_string(pid).c_str(), "oom_score_adj", nullptr);
697
 
    std::string path = gpath;
698
 
    g_free(gpath);
699
 
    return path;
 
966
    auto gpath =
 
967
        unique_gchar(g_build_filename(procpath.c_str(), std::to_string(pid).c_str(), "oom_score_adj", nullptr));
 
968
    return std::string(gpath.get());
700
969
}
701
970
 
702
971
/** Writes an OOM value to proc, assuming we have a string
709
978
{
710
979
    auto oomstr = std::to_string(static_cast<std::int32_t>(oomvalue));
711
980
    auto path = pidToOomPath(pid);
712
 
    FILE* adj = fopen(path.c_str(), "w");
 
981
    ResourcePtr<FILE*, void (*)(FILE*)> adj(fopen(path.c_str(), "w"), [](FILE* fp) {
 
982
        if (fp != nullptr)
 
983
        {
 
984
            fclose(fp);
 
985
        }
 
986
    });
713
987
    int openerr = errno;
714
988
 
715
 
    if (adj == nullptr)
 
989
    if (adj.get() == nullptr)
716
990
    {
717
991
        switch (openerr)
718
992
        {
737
1011
        }
738
1012
    }
739
1013
 
740
 
    size_t writesize = fwrite(oomstr.c_str(), 1, oomstr.size(), adj);
 
1014
    size_t writesize = fwrite(oomstr.c_str(), 1, oomstr.size(), adj.get());
741
1015
    int writeerr = errno;
742
 
    fclose(adj);
 
1016
    adj.dealloc();
743
1017
 
744
1018
    if (writesize == oomstr.size())
745
1019
        return;
765
1039
    std::array<const char*, 4> args = {OOM_HELPER, pidstr.c_str(), oomstr.c_str(), nullptr};
766
1040
 
767
1041
    g_debug("Excuting OOM Helper (pid: %d, score: %d): %s", int(pid), int(oomvalue),
768
 
            std::accumulate(args.begin(), args.end(), std::string{}, [](const std::string& instr,
769
 
                                                                        const char* output) -> std::string {
770
 
                if (instr.empty())
771
 
                {
772
 
                    return output;
773
 
                }
774
 
                else if (output != nullptr)
775
 
                {
776
 
                    return instr + " " + std::string(output);
777
 
                }
778
 
                else
779
 
                {
780
 
                    return instr;
781
 
                }
782
 
            }).c_str());
 
1042
            std::accumulate(args.begin(), args.end(), std::string{},
 
1043
                            [](const std::string& instr, const char* output) -> std::string {
 
1044
                                if (instr.empty())
 
1045
                                {
 
1046
                                    return output;
 
1047
                                }
 
1048
                                else if (output != nullptr)
 
1049
                                {
 
1050
                                    return instr + " " + std::string(output);
 
1051
                                }
 
1052
                                else
 
1053
                                {
 
1054
                                    return instr;
 
1055
                                }
 
1056
                            })
 
1057
                .c_str());
783
1058
 
784
1059
    g_spawn_async(nullptr,               /* working dir */
785
1060
                  (char**)(args.data()), /* args */
802
1077
 
803
1078
    \param urls Vector of URLs to make into C strings
804
1079
*/
805
 
std::shared_ptr<gchar*> Base::urlsToStrv(const std::vector<Application::URL>& urls)
 
1080
GCharVUPtr Base::urlsToStrv(const std::vector<Application::URL>& urls)
806
1081
{
807
1082
    if (urls.empty())
808
1083
    {
809
 
        return {};
 
1084
        return GCharVUPtr(nullptr, &g_strfreev);
810
1085
    }
811
1086
 
812
1087
    auto array = g_array_new(TRUE, FALSE, sizeof(gchar*));
818
1093
        g_array_append_val(array, str);
819
1094
    }
820
1095
 
821
 
    return std::shared_ptr<gchar*>((gchar**)g_array_free(array, FALSE), g_strfreev);
 
1096
    return unique_gcharv((gchar**)g_array_free(array, FALSE));
822
1097
}
823
1098
 
824
1099
}  // namespace instance