Merge lp:~ted/ubuntu-app-launch/jobs-systemd into lp:ubuntu-app-launch/16.10

Proposed by Ted Gould
Status: Superseded
Proposed branch: lp:~ted/ubuntu-app-launch/jobs-systemd
Merge into: lp:ubuntu-app-launch/16.10
Prerequisite: lp:~ted/ubuntu-app-launch/jobs-tests
Diff against target: 1680 lines (+1208/-60)
21 files modified
libubuntu-app-launch/CMakeLists.txt (+4/-0)
libubuntu-app-launch/application-impl-base.cpp (+20/-0)
libubuntu-app-launch/application-impl-base.h (+3/-0)
libubuntu-app-launch/application-impl-click.cpp (+6/-0)
libubuntu-app-launch/application-impl-legacy.cpp (+4/-17)
libubuntu-app-launch/application-impl-legacy.h (+0/-1)
libubuntu-app-launch/application-impl-libertine.cpp (+11/-8)
libubuntu-app-launch/application-impl-snap.cpp (+8/-4)
libubuntu-app-launch/application-info-desktop.cpp (+2/-1)
libubuntu-app-launch/application-info-desktop.h (+8/-0)
libubuntu-app-launch/jobs-base.cpp (+45/-2)
libubuntu-app-launch/jobs-base.h (+8/-0)
libubuntu-app-launch/jobs-systemd.cpp (+950/-0)
libubuntu-app-launch/jobs-systemd.h (+123/-0)
libubuntu-app-launch/jobs-upstart.cpp (+0/-25)
libubuntu-app-launch/registry-impl.cpp (+1/-1)
libubuntu-app-launch/snapd-info.cpp (+1/-1)
tests/exec-util-test.cc (+10/-0)
tests/libual-cpp-test.cc (+1/-0)
tests/libual-test.cc (+1/-0)
xmir-helper.c (+2/-0)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/jobs-systemd
Reviewer Review Type Date Requested Status
Unity API Team Pending
Review via email: mp+309406@code.launchpad.net

This proposal has been superseded by a proposal from 2016-11-10.

Commit message

SystemD backend added

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

Adding in numeric header

310. By Ted Gould

Don't throw an exception when we can't read the file, just assume it is empty

311. By Ted Gould

Merge in the tests branch

312. By Ted Gould

Pulling through updates

313. By Ted Gould

Setup the dbus signal watchers for new and removed units

314. By Ted Gould

Flesh out the unitNew and unitRemoved cache part of the functions

315. By Ted Gould

Emit signals if we see no applications or they disappear

316. By Ted Gould

Use pause and resume from the base class

317. By Ted Gould

We are no emitting valid stopped and started signals

318. By Ted Gould

Switch to the signal based unit cache

319. By Ted Gould

Replace listUnits code with using our unit cache

320. By Ted Gould

Setting up the signal watcher for building the failed signal

321. By Ted Gould

Flesh out the failed signal setup

322. By Ted Gould

Make sure the failure test is still using the Upstart backend

323. By Ted Gould

Debug messages

324. By Ted Gould

Subscribing to events from systemd

325. By Ted Gould

Make sure we get the unit path not just the job path

326. By Ted Gould

Putting in a warning if we're not setting the ExecStart

327. By Ted Gould

Warn if we end up with an odd parse

328. By Ted Gould

Make the code less clever but easier to read and hopefully we can figure out what's going on.

329. By Ted Gould

Pulling through trunk

330. By Ted Gould

Clear out some of the environment variables and check the length

331. By Ted Gould

Keeping libertine launch

332. By Ted Gould

Merge parent

333. By Ted Gould

Test fixes

334. By Ted Gould

Update to the jobs-tests branch updates

335. By Ted Gould

Pull out the registry-mock into it's own file for sharing

336. By Ted Gould

Get in the bones for our testing

337. By Ted Gould

Add in the systemd mock

338. By Ted Gould

Make sure not to use the pointer if we're cancelled

339. By Ted Gould

Build the infrastructure for putting instances in

340. By Ted Gould

Getting our test objects setup

341. By Ted Gould

Add tests to make sure we're initing systemd

342. By Ted Gould

Add a fallback to use the session bus for testing

343. By Ted Gould

Force the systemd unit to session bus

344. By Ted Gould

Make the tests more reliable by waiting on dbus to close

345. By Ted Gould

Ensure that we're immune to very quickly destroyed instances

346. By Ted Gould

Add in a check for an eventually timeout envvar

347. By Ted Gould

Removing fancy async calls

348. By Ted Gould

Setup some 'GetUnit' and more complex mocking for jobs tests

349. By Ted Gould

Don't emit signals on the initial getting a list of units

350. By Ted Gould

Fixing up debug messages

351. By Ted Gould

Make sure to use the registry we have instead of allocating a new one

352. By Ted Gould

A description

353. By Ted Gould

Merge from trunk

354. By Ted Gould

Making it so that we have two multiple and a single

355. By Ted Gould

Apply formatting

356. By Ted Gould

Test to ensure the user bus path is correct

357. By Ted Gould

Adding a test for the PID functions

358. By Ted Gould

Check the stop call code

359. By Ted Gould

Clearing and checking multiple stopping

360. By Ted Gould

Reduce the amount of data needed

361. By Ted Gould

Make a launch test

362. By Ted Gould

First parts of verifying the transient calls

363. By Ted Gould

Environment checking

364. By Ted Gould

Adding in some tests of the instance objects even though they only call into the manager

365. By Ted Gould

Signal new test

366. By Ted Gould

Check signal removed

367. By Ted Gould

Fix for GCC 5.4

368. By Ted Gould

Fail fast

369. By Ted Gould

Okay, that was probably turning it up too high

370. By Ted Gould

Making it so that we throw on errors when building the mock.

371. By Ted Gould

Drop parallel to make builds more reliable

372. By Ted Gould

Make it so that we replace a job on stop

373. By Ted Gould

Update to trunk

374. By Ted Gould

Make getInstance a const method

375. By Ted Gould

Const getAllJobs()

376. By Ted Gould

Comment formatting, whatevs

377. By Ted Gould

Header reshuffle

378. By Ted Gould

Charles hates returns on void functions

379. By Ted Gould

We don't need no stinkin' std::string object

380. By Ted Gould

Remove some printouts when we cancel

381. By Ted Gould

Protect more against null GVariant pointers

382. By Ted Gould

Make the signal handlers safer

383. By Ted Gould

Make parseUnit and unitName const

384. By Ted Gould

Name lamba better

385. By Ted Gould

Use std::vector<> constructor instead of a loop

386. By Ted Gould

Be louder about not having an exec line

387. By Ted Gould

Getting rid of a TODO

388. By Ted Gould

Move declarations

389. By Ted Gould

Avoid calling getenv() twice

390. By Charles Kerr

Cleaner name finding

391. By Ted Gould

Make lists into real lists

392. By Ted Gould

Make sure we don't copy commands

393. By Ted Gould

Making sure we calculate the string once

394. By Ted Gould

Don't get all the jobs until we're sure we have a registry

395. By Ted Gould

Remove try/catch that isn't needed

396. By Ted Gould

Switching to static_cast<>

397. By Ted Gould

Fixing up the failure signals

398. By Charles Kerr

Clearer sorting

399. By Ted Gould

Overrides

400. By Ted Gould

Test the exec line and ensure it doesn't fail

401. By Ted Gould

Don't crash free memory, works but is odd

402. By Ted Gould

Use the g_array functions to avoid some casts

403. By Ted Gould

Making sure everything is on the right bus

Unmerged revisions

403. By Ted Gould

Making sure everything is on the right bus

402. By Ted Gould

Use the g_array functions to avoid some casts

401. By Ted Gould

Don't crash free memory, works but is odd

400. By Ted Gould

Test the exec line and ensure it doesn't fail

399. By Ted Gould

Overrides

398. By Charles Kerr

Clearer sorting

397. By Ted Gould

Fixing up the failure signals

396. By Ted Gould

Switching to static_cast<>

395. By Ted Gould

Remove try/catch that isn't needed

394. By Ted Gould

Don't get all the jobs until we're sure we have a registry

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'libubuntu-app-launch/CMakeLists.txt'
--- libubuntu-app-launch/CMakeLists.txt 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/CMakeLists.txt 2016-11-10 21:59:02 +0000
@@ -17,6 +17,8 @@
17set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wpedantic")17set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wpedantic")
18add_definitions ( -DOOM_HELPER="${pkglibexecdir}/oom-adjust-setuid-helper" -DDEMANGLER_PATH="${pkglibexecdir}/socket-demangler" )18add_definitions ( -DOOM_HELPER="${pkglibexecdir}/oom-adjust-setuid-helper" -DDEMANGLER_PATH="${pkglibexecdir}/socket-demangler" )
19add_definitions ( -DLIBERTINE_LAUNCH="${CMAKE_INSTALL_FULL_BINDIR}/libertine-launch" )19add_definitions ( -DLIBERTINE_LAUNCH="${CMAKE_INSTALL_FULL_BINDIR}/libertine-launch" )
20add_definitions ( -DG_LOG_DOMAIN="ubuntu-app-launch" )
21add_definitions ( -DUBUNTU_APP_LAUNCH_ARCH="${UBUNTU_APP_LAUNCH_ARCH}" )
2022
21set(LAUNCHER_HEADERS23set(LAUNCHER_HEADERS
22ubuntu-app-launch.h24ubuntu-app-launch.h
@@ -54,6 +56,8 @@
54glib-thread.cpp56glib-thread.cpp
55jobs-base.h57jobs-base.h
56jobs-base.cpp58jobs-base.cpp
59jobs-systemd.h
60jobs-systemd.cpp
57jobs-upstart.h61jobs-upstart.h
58jobs-upstart.cpp62jobs-upstart.cpp
59)63)
6064
=== modified file 'libubuntu-app-launch/application-impl-base.cpp'
--- libubuntu-app-launch/application-impl-base.cpp 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/application-impl-base.cpp 2016-11-10 21:59:02 +0000
@@ -95,6 +95,26 @@
95 return retval;95 return retval;
96}96}
9797
98/** Generates an instance string based on the clock if we're a multi-instance
99 application. */
100std::string Base::getInstance(const std::shared_ptr<app_info::Desktop>& desktop)
101{
102 if (!desktop)
103 {
104 g_warning("Invalid desktop file passed to getInstance");
105 return {};
106 }
107
108 if (desktop->singleInstance())
109 {
110 return {};
111 }
112 else
113 {
114 return std::to_string(g_get_real_time());
115 }
116}
117
98} // namespace app_impls118} // namespace app_impls
99} // namespace app_launch119} // namespace app_launch
100} // namespace ubuntu120} // namespace ubuntu
101121
=== modified file 'libubuntu-app-launch/application-impl-base.h'
--- libubuntu-app-launch/application-impl-base.h 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/application-impl-base.h 2016-11-10 21:59:02 +0000
@@ -17,6 +17,7 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include "application-info-desktop.h"
20#include "application.h"21#include "application.h"
2122
22extern "C" {23extern "C" {
@@ -43,6 +44,8 @@
4344
44 bool hasInstances() override;45 bool hasInstances() override;
4546
47 std::string getInstance(const std::shared_ptr<app_info::Desktop>& desktop);
48
46protected:49protected:
47 /** Pointer to the registry so we can ask it for things */50 /** Pointer to the registry so we can ask it for things */
48 std::shared_ptr<Registry> _registry;51 std::shared_ptr<Registry> _registry;
4952
=== modified file 'libubuntu-app-launch/application-impl-click.cpp'
--- libubuntu-app-launch/application-impl-click.cpp 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/application-impl-click.cpp 2016-11-10 21:59:02 +0000
@@ -51,6 +51,8 @@
51 std::tie(_keyfile, desktopPath_) = manifestAppDesktop(_manifest, appid.package, appid.appname, _clickDir);51 std::tie(_keyfile, desktopPath_) = manifestAppDesktop(_manifest, appid.package, appid.appname, _clickDir);
52 if (!_keyfile)52 if (!_keyfile)
53 throw std::runtime_error{"No keyfile found for click application: " + std::string(appid)};53 throw std::runtime_error{"No keyfile found for click application: " + std::string(appid)};
54
55 g_debug("Application Click object for appid '%s'", std::string(appid).c_str());
54}56}
5557
56AppID Click::appId()58AppID Click::appId()
@@ -337,11 +339,15 @@
337 retval.emplace_back(std::make_pair("APP_DIR", _clickDir));339 retval.emplace_back(std::make_pair("APP_DIR", _clickDir));
338 retval.emplace_back(std::make_pair("APP_DESKTOP_FILE_PATH", desktopPath_));340 retval.emplace_back(std::make_pair("APP_DESKTOP_FILE_PATH", desktopPath_));
339341
342 retval.emplace_back(std::make_pair("QML2_IMPORT_PATH", _clickDir + "/lib/" + UBUNTU_APP_LAUNCH_ARCH + "/qml"));
343
340 info();344 info();
341345
342 retval.emplace_back(std::make_pair("APP_XMIR_ENABLE", _info->xMirEnable().value() ? "1" : "0"));346 retval.emplace_back(std::make_pair("APP_XMIR_ENABLE", _info->xMirEnable().value() ? "1" : "0"));
343 retval.emplace_back(std::make_pair("APP_EXEC", _info->execLine().value()));347 retval.emplace_back(std::make_pair("APP_EXEC", _info->execLine().value()));
344348
349 retval.emplace_back(std::make_pair("APP_EXEC_POLICY", std::string(appId())));
350
345 return retval;351 return retval;
346}352}
347353
348354
=== modified file 'libubuntu-app-launch/application-impl-legacy.cpp'
--- libubuntu-app-launch/application-impl-legacy.cpp 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/application-impl-legacy.cpp 2016-11-10 21:59:02 +0000
@@ -74,6 +74,8 @@
74 {74 {
75 throw std::runtime_error{"Looking like a legacy app, but should be a Snap: " + appname.value()};75 throw std::runtime_error{"Looking like a legacy app, but should be a Snap: " + appname.value()};
76 }76 }
77
78 g_debug("Application Legacy object for app '%s'", appname.value().c_str());
77}79}
7880
79std::tuple<std::string, std::shared_ptr<GKeyFile>, std::string> keyfileForApp(const AppID::AppName& name)81std::tuple<std::string, std::shared_ptr<GKeyFile>, std::string> keyfileForApp(const AppID::AppName& name)
@@ -342,21 +344,6 @@
342 return retval;344 return retval;
343}345}
344346
345/** Generates an instance string based on the clock if we're a multi-instance
346 application. */
347std::string Legacy::getInstance()
348{
349 auto single = g_key_file_get_boolean(_keyfile.get(), "Desktop Entry", "X-Ubuntu-Single-Instance", nullptr);
350 if (single)
351 {
352 return {};
353 }
354 else
355 {
356 return std::to_string(g_get_real_time());
357 }
358}
359
360/** Create an UpstartInstance for this AppID using the UpstartInstance launch347/** Create an UpstartInstance for this AppID using the UpstartInstance launch
361 function.348 function.
362349
@@ -364,7 +351,7 @@
364*/351*/
365std::shared_ptr<Application::Instance> Legacy::launch(const std::vector<Application::URL>& urls)352std::shared_ptr<Application::Instance> Legacy::launch(const std::vector<Application::URL>& urls)
366{353{
367 std::string instance = getInstance();354 auto instance = getInstance(appinfo_);
368 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this, instance]() {355 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this, instance]() {
369 return launchEnv(instance);356 return launchEnv(instance);
370 };357 };
@@ -379,7 +366,7 @@
379*/366*/
380std::shared_ptr<Application::Instance> Legacy::launchTest(const std::vector<Application::URL>& urls)367std::shared_ptr<Application::Instance> Legacy::launchTest(const std::vector<Application::URL>& urls)
381{368{
382 std::string instance = getInstance();369 auto instance = getInstance(appinfo_);
383 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this, instance]() {370 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this, instance]() {
384 return launchEnv(instance);371 return launchEnv(instance);
385 };372 };
386373
=== modified file 'libubuntu-app-launch/application-impl-legacy.h'
--- libubuntu-app-launch/application-impl-legacy.h 2016-09-23 21:54:33 +0000
+++ libubuntu-app-launch/application-impl-legacy.h 2016-11-10 21:59:02 +0000
@@ -86,7 +86,6 @@
86 std::regex instanceRegex_;86 std::regex instanceRegex_;
8787
88 std::list<std::pair<std::string, std::string>> launchEnv(const std::string& instance);88 std::list<std::pair<std::string, std::string>> launchEnv(const std::string& instance);
89 std::string getInstance();
90};89};
9190
92} // namespace app_impls91} // namespace app_impls
9392
=== modified file 'libubuntu-app-launch/application-impl-libertine.cpp'
--- libubuntu-app-launch/application-impl-libertine.cpp 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/application-impl-libertine.cpp 2016-11-10 21:59:02 +0000
@@ -65,6 +65,12 @@
65 if (!_keyfile)65 if (!_keyfile)
66 throw std::runtime_error{"Unable to find a keyfile for application '" + appname.value() + "' in container '" +66 throw std::runtime_error{"Unable to find a keyfile for application '" + appname.value() + "' in container '" +
67 container.value() + "'"};67 container.value() + "'"};
68
69 appinfo_ = std::make_shared<app_info::Desktop>(_keyfile, _basedir, _container_path,
70 app_info::DesktopFlags::XMIR_DEFAULT, _registry);
71
72 g_debug("Application Libertine object for container '%s' app '%s'", container.value().c_str(),
73 appname.value().c_str());
68}74}
6975
70std::shared_ptr<GKeyFile> Libertine::keyfileFromPath(const std::string& pathname)76std::shared_ptr<GKeyFile> Libertine::keyfileFromPath(const std::string& pathname)
@@ -265,11 +271,6 @@
265271
266std::shared_ptr<Application::Info> Libertine::info()272std::shared_ptr<Application::Info> Libertine::info()
267{273{
268 if (!appinfo_)
269 {
270 appinfo_ = std::make_shared<app_info::Desktop>(_keyfile, _basedir, _container_path,
271 app_info::DesktopFlags::XMIR_DEFAULT, _registry);
272 }
273 return appinfo_;274 return appinfo_;
274}275}
275276
@@ -317,15 +318,17 @@
317318
318std::shared_ptr<Application::Instance> Libertine::launch(const std::vector<Application::URL>& urls)319std::shared_ptr<Application::Instance> Libertine::launch(const std::vector<Application::URL>& urls)
319{320{
321 auto instance = getInstance(appinfo_);
320 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };322 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };
321 return _registry->impl->jobs->launch(appId(), "application-legacy", {}, urls, jobs::manager::launchMode::STANDARD,323 return _registry->impl->jobs->launch(appId(), "application-legacy", instance, urls,
322 envfunc);324 jobs::manager::launchMode::STANDARD, envfunc);
323}325}
324326
325std::shared_ptr<Application::Instance> Libertine::launchTest(const std::vector<Application::URL>& urls)327std::shared_ptr<Application::Instance> Libertine::launchTest(const std::vector<Application::URL>& urls)
326{328{
329 auto instance = getInstance(appinfo_);
327 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };330 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };
328 return _registry->impl->jobs->launch(appId(), "application-legacy", {}, urls, jobs::manager::launchMode::TEST,331 return _registry->impl->jobs->launch(appId(), "application-legacy", instance, urls, jobs::manager::launchMode::TEST,
329 envfunc);332 envfunc);
330}333}
331334
332335
=== modified file 'libubuntu-app-launch/application-impl-snap.cpp'
--- libubuntu-app-launch/application-impl-snap.cpp 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/application-impl-snap.cpp 2016-11-10 21:59:02 +0000
@@ -196,6 +196,8 @@
196 }196 }
197197
198 info_ = std::make_shared<SnapInfo>(appid_, _registry, interface_, pkgInfo_->directory);198 info_ = std::make_shared<SnapInfo>(appid_, _registry, interface_, pkgInfo_->directory);
199
200 g_debug("Application Snap object for AppID '%s'", std::string(appid).c_str());
199}201}
200202
201/** Uses the findInterface() function to find the interface if we don't203/** Uses the findInterface() function to find the interface if we don't
@@ -229,7 +231,7 @@
229 }231 }
230 catch (std::runtime_error& e)232 catch (std::runtime_error& e)
231 {233 {
232 g_warning("Unable to make Snap object for '%s': %s", std::string(id).c_str(), e.what());234 g_debug("Unable to make Snap object for '%s': %s", std::string(id).c_str(), e.what());
233 }235 }
234 }236 }
235 }237 }
@@ -436,9 +438,10 @@
436*/438*/
437std::shared_ptr<Application::Instance> Snap::launch(const std::vector<Application::URL>& urls)439std::shared_ptr<Application::Instance> Snap::launch(const std::vector<Application::URL>& urls)
438{440{
441 auto instance = getInstance(info_);
439 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };442 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };
440 return _registry->impl->jobs->launch(appid_, "application-snap", {}, urls, jobs::manager::launchMode::STANDARD,443 return _registry->impl->jobs->launch(appid_, "application-snap", instance, urls,
441 envfunc);444 jobs::manager::launchMode::STANDARD, envfunc);
442}445}
443446
444/** Create a new instance of this Snap with a testing environment447/** Create a new instance of this Snap with a testing environment
@@ -448,8 +451,9 @@
448*/451*/
449std::shared_ptr<Application::Instance> Snap::launchTest(const std::vector<Application::URL>& urls)452std::shared_ptr<Application::Instance> Snap::launchTest(const std::vector<Application::URL>& urls)
450{453{
454 auto instance = getInstance(info_);
451 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };455 std::function<std::list<std::pair<std::string, std::string>>(void)> envfunc = [this]() { return launchEnv(); };
452 return _registry->impl->jobs->launch(appid_, "application-snap", {}, urls, jobs::manager::launchMode::TEST,456 return _registry->impl->jobs->launch(appid_, "application-snap", instance, urls, jobs::manager::launchMode::TEST,
453 envfunc);457 envfunc);
454}458}
455459
456460
=== modified file 'libubuntu-app-launch/application-info-desktop.cpp'
--- libubuntu-app-launch/application-info-desktop.cpp 2016-09-14 16:42:20 +0000
+++ libubuntu-app-launch/application-info-desktop.cpp 2016-11-10 21:59:02 +0000
@@ -253,7 +253,7 @@
253 if (stringlistFromKeyfileContains(keyfile, "NotShowIn", xdg_current_desktop, false) ||253 if (stringlistFromKeyfileContains(keyfile, "NotShowIn", xdg_current_desktop, false) ||
254 !stringlistFromKeyfileContains(keyfile, "OnlyShowIn", xdg_current_desktop, true))254 !stringlistFromKeyfileContains(keyfile, "OnlyShowIn", xdg_current_desktop, true))
255 {255 {
256 g_warning("Application is not shown in Unity");256 g_debug("Application is not shown in current desktop: %s", xdg_current_desktop);
257 // Exception removed for OTA11 as a temporary fix257 // Exception removed for OTA11 as a temporary fix
258 // throw std::runtime_error("Application is not shown in Unity");258 // throw std::runtime_error("Application is not shown in Unity");
259 }259 }
@@ -352,6 +352,7 @@
352 , _xMirEnable(352 , _xMirEnable(
353 boolFromKeyfile<XMirEnable>(keyfile, "X-Ubuntu-XMir-Enable", (flags & DesktopFlags::XMIR_DEFAULT).any()))353 boolFromKeyfile<XMirEnable>(keyfile, "X-Ubuntu-XMir-Enable", (flags & DesktopFlags::XMIR_DEFAULT).any()))
354 , _exec(stringFromKeyfile<Exec>(keyfile, "Exec"))354 , _exec(stringFromKeyfile<Exec>(keyfile, "Exec"))
355 , _singleInstance(boolFromKeyfile<SingleInstance>(keyfile, "X-Ubuntu-Single-Instance", false))
355{356{
356}357}
357358
358359
=== modified file 'libubuntu-app-launch/application-info-desktop.h'
--- libubuntu-app-launch/application-info-desktop.h 2016-09-14 16:38:42 +0000
+++ libubuntu-app-launch/application-info-desktop.h 2016-11-10 21:59:02 +0000
@@ -106,6 +106,13 @@
106 return _exec;106 return _exec;
107 }107 }
108108
109 struct SingleInstanceTag;
110 typedef TypeTagger<SingleInstanceTag, bool> SingleInstance;
111 virtual SingleInstance singleInstance()
112 {
113 return _singleInstance;
114 }
115
109protected:116protected:
110 std::shared_ptr<GKeyFile> _keyfile;117 std::shared_ptr<GKeyFile> _keyfile;
111 std::string _basePath;118 std::string _basePath;
@@ -125,6 +132,7 @@
125132
126 XMirEnable _xMirEnable;133 XMirEnable _xMirEnable;
127 Exec _exec;134 Exec _exec;
135 SingleInstance _singleInstance;
128};136};
129137
130} // namespace AppInfo138} // namespace AppInfo
131139
=== modified file 'libubuntu-app-launch/jobs-base.cpp'
--- libubuntu-app-launch/jobs-base.cpp 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/jobs-base.cpp 2016-11-10 21:59:02 +0000
@@ -23,6 +23,7 @@
23#include <numeric>23#include <numeric>
2424
25#include "jobs-base.h"25#include "jobs-base.h"
26#include "jobs-systemd.h"
26#include "jobs-upstart.h"27#include "jobs-upstart.h"
27#include "registry-impl.h"28#include "registry-impl.h"
2829
@@ -37,6 +38,7 @@
3738
38Base::Base(const std::shared_ptr<Registry>& registry)39Base::Base(const std::shared_ptr<Registry>& registry)
39 : registry_(registry)40 : registry_(registry)
41 , allJobs_{"application-click", "application-legacy", "application-snap"}
40 , dbus_(registry->impl->_dbus)42 , dbus_(registry->impl->_dbus)
41{43{
42}44}
@@ -58,7 +60,23 @@
5860
59std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry)61std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry)
60{62{
61 return std::make_shared<jobs::manager::Upstart>(registry);63 /* Checking to see if we have a user bus, that is only started
64 by systemd so we're in good shape if we have one. We're using
65 the path instead of the RUNTIME variable because we want to work
66 around the case of being relocated by the snappy environment */
67 if (g_file_test(SystemD::userBusPath().c_str(), G_FILE_TEST_EXISTS))
68 {
69 return std::make_shared<jobs::manager::SystemD>(registry);
70 }
71 else
72 {
73 return std::make_shared<jobs::manager::Upstart>(registry);
74 }
75}
76
77const std::set<std::string>& Base::getAllJobs()
78{
79 return allJobs_;
62}80}
6381
64/** Take the GVariant of parameters and turn them into an application and82/** Take the GVariant of parameters and turn them into an application and
@@ -277,7 +295,9 @@
277bool Base::hasPid(pid_t pid)295bool Base::hasPid(pid_t pid)
278{296{
279 auto vpids = pids();297 auto vpids = pids();
280 return std::find(vpids.begin(), vpids.end(), pid) != vpids.end();298 bool hasit = std::find(vpids.begin(), vpids.end(), pid) != vpids.end();
299 g_debug("Checking for PID %d on AppID '%s' result: %s", pid, std::string(appId_).c_str(), hasit ? "YES" : "NO");
300 return hasit;
281}301}
282302
283/** Pauses this application by sending SIGSTOP to all the PIDs in the303/** Pauses this application by sending SIGSTOP to all the PIDs in the
@@ -585,6 +605,29 @@
585 }605 }
586}606}
587607
608/** Reformat a C++ vector of URLs into a C GStrv of strings
609
610 \param urls Vector of URLs to make into C strings
611*/
612std::shared_ptr<gchar*> Base::urlsToStrv(const std::vector<Application::URL>& urls)
613{
614 if (urls.empty())
615 {
616 return {};
617 }
618
619 auto array = g_array_new(TRUE, FALSE, sizeof(gchar*));
620
621 for (auto url : urls)
622 {
623 auto str = g_strdup(url.value().c_str());
624 g_debug("Converting URL: %s", str);
625 g_array_append_val(array, str);
626 }
627
628 return std::shared_ptr<gchar*>((gchar**)g_array_free(array, FALSE), g_strfreev);
629}
630
588} // namespace instance631} // namespace instance
589632
590} // namespace jobs633} // namespace jobs
591634
=== modified file 'libubuntu-app-launch/jobs-base.h'
--- libubuntu-app-launch/jobs-base.h 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/jobs-base.h 2016-11-10 21:59:02 +0000
@@ -24,6 +24,7 @@
2424
25#include <core/signal.h>25#include <core/signal.h>
26#include <gio/gio.h>26#include <gio/gio.h>
27#include <set>
2728
28namespace ubuntu29namespace ubuntu
29{30{
@@ -66,6 +67,8 @@
66 /** A link to the registry we're using for connections */67 /** A link to the registry we're using for connections */
67 std::shared_ptr<Registry> registry_;68 std::shared_ptr<Registry> registry_;
6869
70 static std::shared_ptr<gchar*> urlsToStrv(const std::vector<Application::URL>& urls);
71
69private:72private:
70 std::vector<pid_t> forAllPids(std::function<void(pid_t)> eachPid);73 std::vector<pid_t> forAllPids(std::function<void(pid_t)> eachPid);
71 void signalToPid(pid_t pid, int signal);74 void signalToPid(pid_t pid, int signal);
@@ -110,6 +113,8 @@
110113
111 virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) = 0;114 virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) = 0;
112115
116 const std::set<std::string>& getAllJobs();
117
113 static std::shared_ptr<Base> determineFactory(std::shared_ptr<Registry> registry);118 static std::shared_ptr<Base> determineFactory(std::shared_ptr<Registry> registry);
114119
115 /* Signals to apps */120 /* Signals to apps */
@@ -130,6 +135,9 @@
130 /** A link to the registry */135 /** A link to the registry */
131 std::weak_ptr<Registry> registry_;136 std::weak_ptr<Registry> registry_;
132137
138 /** A set of all the job names */
139 std::set<std::string> allJobs_;
140
133 /** The DBus connection we're connecting to */141 /** The DBus connection we're connecting to */
134 std::shared_ptr<GDBusConnection> dbus_;142 std::shared_ptr<GDBusConnection> dbus_;
135143
136144
=== added file 'libubuntu-app-launch/jobs-systemd.cpp'
--- libubuntu-app-launch/jobs-systemd.cpp 1970-01-01 00:00:00 +0000
+++ libubuntu-app-launch/jobs-systemd.cpp 2016-11-10 21:59:02 +0000
@@ -0,0 +1,950 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#include <algorithm>
21#include <gio/gio.h>
22#include <numeric>
23#include <regex>
24#include <sys/types.h>
25#include <unistd.h>
26
27#include "helpers.h"
28#include "jobs-systemd.h"
29#include "registry-impl.h"
30#include "second-exec-core.h"
31
32extern "C" {
33#include "ubuntu-app-launch-trace.h"
34}
35
36namespace ubuntu
37{
38namespace app_launch
39{
40namespace jobs
41{
42namespace instance
43{
44
45class SystemD : public Base
46{
47 friend class manager::SystemD;
48
49public:
50 explicit SystemD(const AppID& appId,
51 const std::string& job,
52 const std::string& instance,
53 const std::vector<Application::URL>& urls,
54 const std::shared_ptr<Registry>& registry);
55
56 /* Query lifecycle */
57 pid_t primaryPid() override;
58 std::string logPath() override;
59 std::vector<pid_t> pids() override;
60
61 /* Manage lifecycle */
62 void stop() override;
63
64}; // class SystemD
65
66SystemD::SystemD(const AppID& appId,
67 const std::string& job,
68 const std::string& instance,
69 const std::vector<Application::URL>& urls,
70 const std::shared_ptr<Registry>& registry)
71 : Base(appId, job, instance, urls, registry)
72{
73 g_debug("Creating a new SystemD for '%s' instance '%s'", std::string(appId).c_str(), instance.c_str());
74}
75
76pid_t SystemD::primaryPid()
77{
78 auto manager = std::dynamic_pointer_cast<manager::SystemD>(registry_->impl->jobs);
79 return manager->unitPrimaryPid(appId_, job_, instance_);
80}
81
82std::string SystemD::logPath()
83{
84 /* NOTE: We can never get this for systemd */
85 return {};
86}
87
88std::vector<pid_t> SystemD::pids()
89{
90 auto manager = std::dynamic_pointer_cast<manager::SystemD>(registry_->impl->jobs);
91 return manager->unitPids(appId_, job_, instance_);
92}
93
94void SystemD::stop()
95{
96 auto manager = std::dynamic_pointer_cast<manager::SystemD>(registry_->impl->jobs);
97 return manager->stopUnit(appId_, job_, instance_);
98}
99
100} // namespace instance
101
102namespace manager
103{
104
105static const std::string SYSTEMD_DBUS_ADDRESS{"org.freedesktop.systemd1"};
106static const std::string SYSTEMD_DBUS_IFACE_MANAGER{"org.freedesktop.systemd1.Manager"};
107static const std::string SYSTEMD_DBUS_PATH_MANAGER{"/org/freedesktop/systemd1"};
108static const std::string SYSTEMD_DBUS_IFACE_UNIT{"org.freedesktop.systemd1.Unit"};
109static const std::string SYSTEMD_DBUS_IFACE_SERVICE{"org.freedesktop.systemd1.Service"};
110
111SystemD::SystemD(std::shared_ptr<Registry> registry)
112 : Base(registry)
113{
114 auto cancel = registry->impl->thread.getCancellable();
115 userbus_ = registry->impl->thread.executeOnThread<std::shared_ptr<GDBusConnection>>([cancel]() {
116 GError* error = nullptr;
117 auto bus = std::shared_ptr<GDBusConnection>(
118 g_dbus_connection_new_for_address_sync(
119 ("unix:path=" + userBusPath()).c_str(), /* path to the user bus */
120 (GDBusConnectionFlags)(G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
121 G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION), /* It is a message bus */
122 nullptr, /* observer */
123 cancel.get(), /* cancellable from the thread */
124 &error), /* error */
125 [](GDBusConnection* bus) { g_clear_object(&bus); });
126
127 if (error != nullptr)
128 {
129 std::string message = std::string("Unable to connect to user bus: ") + error->message;
130 g_error_free(error);
131 throw std::runtime_error(message);
132 }
133
134 return bus;
135 });
136}
137
138SystemD::~SystemD()
139{
140}
141
142std::string SystemD::findEnv(const std::string& value, std::list<std::pair<std::string, std::string>>& env)
143{
144 std::string retval;
145 auto entry = std::find_if(env.begin(), env.end(),
146 [&value](std::pair<std::string, std::string>& entry) { return entry.first == value; });
147
148 if (entry != env.end())
149 {
150 retval = entry->second;
151 }
152
153 return retval;
154}
155
156std::vector<std::string> SystemD::parseExec(std::list<std::pair<std::string, std::string>>& env)
157{
158 auto exec = findEnv("APP_EXEC", env);
159 if (exec.empty())
160 {
161 g_debug("Application exec line is empty?!?!?");
162 return {};
163 }
164 auto uris = findEnv("APP_URIS", env);
165
166 auto execarray = desktop_exec_parse(exec.c_str(), uris.c_str());
167
168 std::vector<std::string> retval;
169 retval.reserve(execarray->len);
170 for (unsigned int i = 0; i < execarray->len; i++)
171 {
172 retval.emplace_back(g_array_index(execarray, gchar*, i));
173 }
174
175 g_array_set_clear_func(execarray, g_free);
176 g_array_free(execarray, FALSE); /* TODO: Not TRUE? */
177
178 /* See if we need the xmir helper */
179 if (findEnv("APP_XMIR_ENABLE", env) == "1" && getenv("DISPLAY") == nullptr)
180 {
181 retval.emplace(retval.begin(), findEnv("APP_ID", env));
182 retval.emplace(retval.begin(), XMIR_HELPER);
183 }
184
185 /* See if we're doing apparmor by hand */
186 auto appexecpolicy = findEnv("APP_EXEC_POLICY", env);
187 if (!appexecpolicy.empty() && appexecpolicy != "unconfined")
188 {
189 retval.emplace(retval.begin(), appexecpolicy);
190 retval.emplace(retval.begin(), "-p");
191 retval.emplace(retval.begin(), "aa-exec");
192 }
193
194 return retval;
195}
196
197/** Small helper that we can new/delete to work better with C stuff */
198struct StartCHelper
199{
200 std::shared_ptr<instance::SystemD> ptr;
201 std::shared_ptr<GDBusConnection> bus;
202};
203
204void SystemD::application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data)
205{
206 auto data = static_cast<StartCHelper*>(user_data);
207 GError* error{nullptr};
208 GVariant* result{nullptr};
209
210 tracepoint(ubuntu_app_launch, libual_start_message_callback, std::string(data->ptr->appId_).c_str());
211
212 g_debug("Started Message Callback: %s", std::string(data->ptr->appId_).c_str());
213
214 result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error);
215
216 g_clear_pointer(&result, g_variant_unref);
217
218 if (error != nullptr)
219 {
220 if (g_dbus_error_is_remote_error(error))
221 {
222 gchar* remote_error = g_dbus_error_get_remote_error(error);
223 g_debug("Remote error: %s", remote_error);
224 if (g_strcmp0(remote_error, "org.freedesktop.systemd1.UnitExists") == 0)
225 {
226 auto urls = instance::SystemD::urlsToStrv(data->ptr->urls_);
227 second_exec(data->bus.get(), /* DBus */
228 data->ptr->registry_->impl->thread.getCancellable().get(), /* cancellable */
229 data->ptr->primaryPid(), /* primary pid */
230 std::string(data->ptr->appId_).c_str(), /* appid */
231 urls.get()); /* urls */
232 }
233
234 g_free(remote_error);
235 }
236 else
237 {
238 g_warning("Unable to emit event to start application: %s", error->message);
239 }
240 g_error_free(error);
241 }
242
243 delete data;
244}
245
246void SystemD::copyEnv(const std::string& envname, std::list<std::pair<std::string, std::string>>& env)
247{
248 if (!findEnv(envname, env).empty())
249 {
250 g_debug("Already a value set for '%s' ignoring", envname.c_str());
251 return;
252 }
253
254 auto cvalue = getenv(envname.c_str());
255 g_debug("Copying Environment: %s", envname.c_str());
256 if (cvalue != nullptr)
257 {
258 std::string value = getenv(envname.c_str());
259 env.emplace_back(std::make_pair(envname, value));
260 }
261 else
262 {
263 g_debug("Unable to copy environment '%s'", envname.c_str());
264 }
265}
266
267void SystemD::copyEnvByPrefix(const std::string& prefix, std::list<std::pair<std::string, std::string>>& env)
268{
269 for (unsigned int i = 0; environ[i] != nullptr; i++)
270 {
271 if (g_str_has_prefix(environ[i], prefix.c_str()))
272 {
273 std::string envfull = environ[i];
274 std::string envname;
275 bool seenequal = false;
276 std::remove_copy_if(envfull.begin(), envfull.end(), std::back_inserter(envname),
277 [&seenequal](const char c) {
278 if (c == '=')
279 {
280 seenequal = true;
281 }
282 return seenequal;
283 });
284 copyEnv(envname, env);
285 }
286 }
287}
288
289std::shared_ptr<Application::Instance> SystemD::launch(
290 const AppID& appId,
291 const std::string& job,
292 const std::string& instance,
293 const std::vector<Application::URL>& urls,
294 launchMode mode,
295 std::function<std::list<std::pair<std::string, std::string>>(void)>& getenv)
296{
297 if (appId.empty())
298 return {};
299
300 auto registry = registry_.lock();
301 return registry->impl->thread.executeOnThread<std::shared_ptr<instance::SystemD>>(
302 [&]() -> std::shared_ptr<instance::SystemD> {
303 auto manager = std::dynamic_pointer_cast<manager::SystemD>(registry->impl->jobs);
304 std::string appIdStr{appId};
305 g_debug("Initializing params for an new instance::SystemD for: %s", appIdStr.c_str());
306
307 tracepoint(ubuntu_app_launch, libual_start, appIdStr.c_str());
308
309 int timeout = 1;
310 if (ubuntu::app_launch::Registry::Impl::isWatchingAppStarting())
311 {
312 timeout = 0;
313 }
314
315 auto handshake = starting_handshake_start(appIdStr.c_str(), timeout);
316 if (handshake == nullptr)
317 {
318 g_warning("Unable to setup starting handshake");
319 }
320
321 /* Figure out the unit name for the job */
322 auto unitname = unitName(SystemD::UnitInfo{appIdStr, job, instance});
323
324 /* Build up our environment */
325 auto env = getenv();
326
327 env.emplace_back(std::make_pair("APP_ID", appIdStr)); /* Application ID */
328 env.emplace_back(std::make_pair("APP_LAUNCHER_PID", std::to_string(getpid()))); /* Who we are, for bugs */
329
330 copyEnv("DISPLAY", env);
331 copyEnvByPrefix("DBUS_", env);
332 copyEnvByPrefix("MIR_", env);
333 copyEnvByPrefix("QT_", env);
334 copyEnvByPrefix("UBUNTU_", env);
335 copyEnvByPrefix("UNITY_", env);
336 copyEnvByPrefix("XDG_", env);
337
338 if (!urls.empty())
339 {
340 auto accumfunc = [](const std::string& prev, Application::URL thisurl) -> std::string {
341 gchar* gescaped = g_shell_quote(thisurl.value().c_str());
342 std::string escaped;
343 if (gescaped != nullptr)
344 {
345 escaped = gescaped;
346 g_free(gescaped);
347 }
348 else
349 {
350 g_warning("Unable to escape URL: %s", thisurl.value().c_str());
351 return prev;
352 }
353
354 if (prev.empty())
355 {
356 return escaped;
357 }
358 else
359 {
360 return prev + " " + escaped;
361 }
362 };
363 auto urlstring = std::accumulate(urls.begin(), urls.end(), std::string{}, accumfunc);
364 env.emplace_back(std::make_pair("APP_URIS", urlstring));
365 }
366
367 if (mode == launchMode::TEST)
368 {
369 env.emplace_back(std::make_pair("QT_LOAD_TESTABILITY", "1"));
370 }
371
372 /* Convert to GVariant */
373 GVariantBuilder builder;
374 g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
375
376 g_variant_builder_add_value(&builder, g_variant_new_string(unitname.c_str()));
377 g_variant_builder_add_value(&builder, g_variant_new_string("replace")); // Job mode
378
379 /* Parameter Array */
380 g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
381
382 /* Environment */
383 g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE);
384 g_variant_builder_add_value(&builder, g_variant_new_string("Environment"));
385 g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT);
386 g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
387 for (const auto& envvar : env)
388 {
389 if (!envvar.first.empty() && !envvar.second.empty())
390 {
391 g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf(
392 "%s=%s", envvar.first.c_str(), envvar.second.c_str())));
393 // g_debug("Setting environment: %s=%s", envvar.first.c_str(), envvar.second.c_str());
394 }
395 }
396
397 g_variant_builder_close(&builder);
398 g_variant_builder_close(&builder);
399 g_variant_builder_close(&builder);
400
401 /* ExecStart */
402 auto commands = parseExec(env);
403 gchar* pathexec{nullptr};
404 if (!commands.empty() && ((pathexec = g_find_program_in_path(commands[0].c_str())) != nullptr))
405 {
406 g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE);
407 g_variant_builder_add_value(&builder, g_variant_new_string("ExecStart"));
408 g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT);
409 g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
410
411 g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE);
412 g_variant_builder_add_value(&builder, g_variant_new_take_string(pathexec));
413
414 g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY);
415 for (auto param : commands)
416 {
417 g_variant_builder_add_value(&builder, g_variant_new_string(param.c_str()));
418 }
419 g_variant_builder_close(&builder);
420
421 g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE));
422
423 g_variant_builder_close(&builder);
424 g_variant_builder_close(&builder);
425 g_variant_builder_close(&builder);
426 g_variant_builder_close(&builder);
427 }
428
429 /* RemainAfterExit */
430 g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE);
431 g_variant_builder_add_value(&builder, g_variant_new_string("RemainAfterExit"));
432 g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT);
433 g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE));
434 g_variant_builder_close(&builder);
435 g_variant_builder_close(&builder);
436
437 /* Type */
438 g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE);
439 g_variant_builder_add_value(&builder, g_variant_new_string("Type"));
440 g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT);
441 g_variant_builder_add_value(&builder, g_variant_new_string("oneshot"));
442 g_variant_builder_close(&builder);
443 g_variant_builder_close(&builder);
444
445 /* Working Directory */
446 if (!findEnv("APP_DIR", env).empty())
447 {
448 g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE);
449 g_variant_builder_add_value(&builder, g_variant_new_string("WorkingDirectory"));
450 g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT);
451 g_variant_builder_add_value(&builder, g_variant_new_string(findEnv("APP_DIR", env).c_str()));
452 g_variant_builder_close(&builder);
453 g_variant_builder_close(&builder);
454 }
455
456 /* Parameter Array */
457 g_variant_builder_close(&builder);
458
459 /* Dependent Units (none) */
460 g_variant_builder_add_value(&builder, g_variant_new_array(G_VARIANT_TYPE("(sa(sv))"), nullptr, 0));
461
462 auto retval = std::make_shared<instance::SystemD>(appId, job, instance, urls, registry);
463 auto chelper = new StartCHelper{};
464 chelper->ptr = retval;
465 chelper->bus = manager->userbus_;
466
467 tracepoint(ubuntu_app_launch, handshake_wait, appIdStr.c_str());
468 starting_handshake_wait(handshake);
469 tracepoint(ubuntu_app_launch, handshake_complete, appIdStr.c_str());
470
471 /* Call the job start function */
472 g_debug("Asking systemd to start task for: %s", appIdStr.c_str());
473 g_dbus_connection_call(manager->userbus_.get(), /* bus */
474 SYSTEMD_DBUS_ADDRESS.c_str(), /* service name */
475 SYSTEMD_DBUS_PATH_MANAGER.c_str(), /* Path */
476 SYSTEMD_DBUS_IFACE_MANAGER.c_str(), /* interface */
477 "StartTransientUnit", /* method */
478 g_variant_builder_end(&builder), /* params */
479 G_VARIANT_TYPE("(o)"), /* return */
480 G_DBUS_CALL_FLAGS_NONE, /* flags */
481 -1, /* default timeout */
482 registry->impl->thread.getCancellable().get(), /* cancellable */
483 application_start_cb, /* callback */
484 chelper /* object */
485 );
486
487 tracepoint(ubuntu_app_launch, libual_start_message_sent, appIdStr.c_str());
488
489 return retval;
490 });
491}
492
493std::shared_ptr<Application::Instance> SystemD::existing(const AppID& appId,
494 const std::string& job,
495 const std::string& instance,
496 const std::vector<Application::URL>& urls)
497{
498 return std::make_shared<instance::SystemD>(appId, job, instance, urls, registry_.lock());
499}
500
501std::vector<std::shared_ptr<instance::Base>> SystemD::instances(const AppID& appID, const std::string& job)
502{
503 std::vector<std::shared_ptr<instance::Base>> instances;
504 auto registry = registry_.lock();
505 std::vector<Application::URL> urls;
506
507 for (const auto& unit : listUnits())
508 {
509 SystemD::UnitInfo unitinfo;
510
511 try
512 {
513 unitinfo = parseUnit(unit.id);
514 }
515 catch (std::runtime_error& e)
516 {
517 continue;
518 }
519
520 if (job != unitinfo.job)
521 {
522 continue;
523 }
524
525 if (std::string(appID) != unitinfo.appid)
526 {
527 continue;
528 }
529
530 instances.emplace_back(std::make_shared<instance::SystemD>(appID, job, unitinfo.inst, urls, registry));
531 }
532
533 g_debug("Found %d instances for AppID '%s'", int(instances.size()), std::string(appID).c_str());
534
535 return instances;
536}
537
538std::list<std::shared_ptr<Application>> SystemD::runningApps()
539{
540 auto allJobs = getAllJobs();
541 auto registry = registry_.lock();
542 std::set<std::string> appids;
543
544 for (const auto& unit : listUnits())
545 {
546 SystemD::UnitInfo unitinfo;
547
548 try
549 {
550 unitinfo = parseUnit(unit.id);
551 }
552 catch (std::runtime_error& e)
553 {
554 continue;
555 }
556
557 if (allJobs.find(unitinfo.job) == allJobs.end())
558 {
559 continue;
560 }
561
562 appids.insert(unitinfo.appid);
563 }
564
565 std::list<std::shared_ptr<Application>> apps;
566 for (const auto& appid : appids)
567 {
568 auto id = AppID::find(appid);
569 if (id.empty())
570 {
571 g_debug("Unable to handle AppID: %s", appid.c_str());
572 continue;
573 }
574
575 apps.emplace_back(Application::create(id, registry));
576 }
577
578 return apps;
579}
580
581std::string SystemD::userBusPath()
582{
583 auto cpath = getenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH");
584 if (cpath != nullptr)
585 {
586 return cpath;
587 }
588 return std::string{"/run/user/"} + std::to_string(getuid()) + std::string{"/bus"};
589}
590
591std::list<SystemD::UnitEntry> SystemD::listUnits()
592{
593 auto registry = registry_.lock();
594 return registry->impl->thread.executeOnThread<std::list<SystemD::UnitEntry>>([this, registry]() {
595 GError* error{nullptr};
596 std::list<SystemD::UnitEntry> ret;
597
598 GVariant* callt = g_dbus_connection_call_sync(userbus_.get(), /* user bus */
599 SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */
600 SYSTEMD_DBUS_PATH_MANAGER.c_str(), /* path */
601 SYSTEMD_DBUS_IFACE_MANAGER.c_str(), /* interface */
602 "ListUnits", /* method */
603 nullptr, /* params */
604 G_VARIANT_TYPE("(a(ssssssouso))"), /* ret type */
605 G_DBUS_CALL_FLAGS_NONE, /* flags */
606 -1, /* timeout */
607 registry->impl->thread.getCancellable().get(), /* cancellable */
608 &error);
609
610 if (error != nullptr)
611 {
612 auto message = std::string{"Unable to list SystemD units: "} + error->message;
613 g_error_free(error);
614 throw std::runtime_error(message);
615 }
616
617 GVariant* call = g_variant_get_child_value(callt, 0);
618 g_variant_unref(callt);
619
620 const gchar* id;
621 const gchar* description;
622 const gchar* loadState;
623 const gchar* activeState;
624 const gchar* subState;
625 const gchar* following;
626 const gchar* path;
627 guint32 jobId;
628 const gchar* jobType;
629 const gchar* jobPath;
630 auto iter = g_variant_iter_new(call);
631 while (g_variant_iter_loop(iter, "(&s&s&s&s&s&s&ou&s&o)", &id, &description, &loadState, &activeState,
632 &subState, &following, &path, &jobId, &jobType, &jobPath))
633 {
634 ret.emplace_back(SystemD::UnitEntry{id, description, loadState, activeState, subState, following, path,
635 jobId, jobType, jobPath});
636 }
637
638 g_variant_iter_free(iter);
639 g_variant_unref(call);
640
641 return ret;
642 });
643}
644
645/* TODO: Application job names */
646const std::regex unitNaming{
647 "^ubuntu\\-app\\-launch\\-(application\\-(?:click|legacy|snap))\\-(.*)\\-([0-9]*)\\.service$"};
648
649SystemD::UnitInfo SystemD::parseUnit(const std::string& unit)
650{
651 std::smatch match;
652 if (!std::regex_match(unit, match, unitNaming))
653 {
654 throw std::runtime_error{"Unable to parse unit name: " + unit};
655 }
656
657 return {match[2].str(), match[1].str(), match[3].str()};
658}
659
660std::string SystemD::unitName(const SystemD::UnitInfo& info)
661{
662 return std::string{"ubuntu-app-launch-"} + info.job + "-" + info.appid + "-" + info.inst + ".service";
663}
664
665/** Function that uses and maintains the cache of the paths for units
666 on the systemd dbus connection. If we already have the entry in the
667 cache we just return the path and this function is fast. If not we have
668 to ask systemd for it and that can take a bit longer.
669
670 After getting the data we throw a small background task in to clean
671 up the cache if it has more than 50 entries. We delete those who
672 haven't be used for an hour.
673*/
674std::string SystemD::unitPath(const std::string& unitName)
675{
676 auto registry = registry_.lock();
677 std::string retval;
678
679 if (true)
680 {
681 /* Create a context for the gaurd */
682 std::lock_guard<std::mutex> guard(unitPathsMutex_);
683 auto iter = std::find_if(unitPaths_.begin(), unitPaths_.end(),
684 [&unitName](const SystemD::UnitPath& entry) { return entry.unitName == unitName; });
685
686 if (iter != unitPaths_.end())
687 {
688 retval = iter->unitPath;
689 iter->timeStamp = std::chrono::system_clock::now();
690 }
691 }
692
693 if (retval.empty())
694 {
695 retval = registry->impl->thread.executeOnThread<std::string>([this, registry, unitName]() {
696 std::string path;
697 GError* error{nullptr};
698 GVariant* call =
699 g_dbus_connection_call_sync(userbus_.get(), /* user bus */
700 SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */
701 SYSTEMD_DBUS_PATH_MANAGER.c_str(), /* path */
702 SYSTEMD_DBUS_IFACE_MANAGER.c_str(), /* interface */
703 "GetUnit", /* method */
704 g_variant_new("(s)", unitName.c_str()), /* params */
705 G_VARIANT_TYPE("(o)"), /* ret type */
706 G_DBUS_CALL_FLAGS_NONE, /* flags */
707 -1, /* timeout */
708 registry->impl->thread.getCancellable().get(), /* cancellable */
709 &error);
710
711 if (error != nullptr)
712 {
713 auto message = std::string{"Unable to get SystemD unit path for '"} + unitName + std::string{"': "} +
714 error->message;
715 g_error_free(error);
716 throw std::runtime_error(message);
717 }
718
719 /* Parse variant */
720 gchar* gpath = nullptr;
721 g_variant_get(call, "(o)", &gpath);
722 if (gpath != nullptr)
723 {
724 std::lock_guard<std::mutex> guard(unitPathsMutex_);
725 path = gpath;
726 unitPaths_.emplace_back(SystemD::UnitPath{unitName, path, std::chrono::system_clock::now()});
727 }
728
729 g_variant_unref(call);
730
731 return path;
732 });
733 }
734
735 /* Queue a possible cleanup */
736 if (unitPaths_.size() > 50)
737 {
738 /* TODO: We should look at UnitRemoved as well */
739 /* TODO: Add to cache on UnitNew */
740 registry->impl->thread.executeOnThread([this] {
741 std::lock_guard<std::mutex> guard(unitPathsMutex_);
742 std::remove_if(unitPaths_.begin(), unitPaths_.end(), [](const SystemD::UnitPath& entry) -> bool {
743 auto age = std::chrono::system_clock::now() - entry.timeStamp;
744 return age > std::chrono::hours{1};
745 });
746 });
747 }
748
749 return retval;
750}
751
752pid_t SystemD::unitPrimaryPid(const AppID& appId, const std::string& job, const std::string& instance)
753{
754 auto registry = registry_.lock();
755 auto unitname = unitName(SystemD::UnitInfo{appId, job, instance});
756 auto unitpath = unitPath(unitname);
757
758 return registry->impl->thread.executeOnThread<pid_t>([this, registry, unitname, unitpath]() {
759 GError* error{nullptr};
760 GVariant* call = g_dbus_connection_call_sync(
761 userbus_.get(), /* user bus */
762 SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */
763 unitpath.c_str(), /* path */
764 "org.freedesktop.DBus.Properties", /* interface */
765 "Get", /* method */
766 g_variant_new("(ss)", SYSTEMD_DBUS_IFACE_SERVICE.c_str(), "MainPID"), /* params */
767 G_VARIANT_TYPE("(v)"), /* ret type */
768 G_DBUS_CALL_FLAGS_NONE, /* flags */
769 -1, /* timeout */
770 registry->impl->thread.getCancellable().get(), /* cancellable */
771 &error);
772
773 if (error != nullptr)
774 {
775 auto message =
776 std::string{"Unable to get SystemD PID for '"} + unitname + std::string{"': "} + error->message;
777 g_error_free(error);
778 throw std::runtime_error(message);
779 }
780
781 /* Parse variant */
782 GVariant* vpid{nullptr};
783 g_variant_get(call, "(v)", &vpid);
784 g_variant_unref(call);
785
786 pid_t pid;
787 pid = g_variant_get_uint32(vpid);
788 g_variant_unref(vpid);
789
790 return pid;
791 });
792}
793
794std::vector<pid_t> SystemD::unitPids(const AppID& appId, const std::string& job, const std::string& instance)
795{
796 auto registry = registry_.lock();
797 auto unitname = unitName(SystemD::UnitInfo{appId, job, instance});
798 auto unitpath = unitPath(unitname);
799
800 auto cgrouppath = registry->impl->thread.executeOnThread<std::string>([this, registry, unitname, unitpath]() {
801 GError* error{nullptr};
802 GVariant* call = g_dbus_connection_call_sync(
803 userbus_.get(), /* user bus */
804 SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */
805 unitpath.c_str(), /* path */
806 "org.freedesktop.DBus.Properties", /* interface */
807 "Get", /* method */
808 g_variant_new("(ss)", SYSTEMD_DBUS_IFACE_SERVICE.c_str(), "ControlGroup"), /* params */
809 G_VARIANT_TYPE("(v)"), /* ret type */
810 G_DBUS_CALL_FLAGS_NONE, /* flags */
811 -1, /* timeout */
812 registry->impl->thread.getCancellable().get(), /* cancellable */
813 &error);
814
815 if (error != nullptr)
816 {
817 auto message = std::string{"Unable to get SystemD Control Group for '"} + unitname + std::string{"': "} +
818 error->message;
819 g_error_free(error);
820 throw std::runtime_error(message);
821 }
822
823 /* Parse variant */
824 GVariant* vstring = nullptr;
825 g_variant_get(call, "(v)", &vstring);
826 g_variant_unref(call);
827
828 if (vstring == nullptr)
829 {
830 return std::string{};
831 }
832
833 std::string group;
834 auto ggroup = g_variant_get_string(vstring, nullptr);
835 if (ggroup != nullptr)
836 {
837 group = ggroup;
838 }
839 g_variant_unref(vstring);
840
841 return group;
842 });
843
844 gchar* fullpath = g_build_filename("/sys", "fs", "cgroup", "systemd", cgrouppath.c_str(), "tasks", nullptr);
845 gchar* pidstr = nullptr;
846 GError* error = nullptr;
847
848 g_debug("Getting PIDs from %s", fullpath);
849 g_file_get_contents(fullpath, &pidstr, nullptr, &error);
850 g_free(fullpath);
851
852 if (error != nullptr)
853 {
854 g_warning("Unable to read cgroup PID list: %s", error->message);
855 g_error_free(error);
856 return {};
857 }
858
859 gchar** pidlines = g_strsplit(pidstr, "\n", -1);
860 g_free(pidstr);
861 std::vector<pid_t> pids;
862
863 for (auto i = 0; pidlines[i] != nullptr; i++)
864 {
865 const gchar* pidline = pidlines[i];
866 if (pidline[0] != '\n')
867 {
868 auto pid = std::atoi(pidline);
869 if (pid != 0)
870 {
871 pids.emplace_back(pid);
872 }
873 }
874 }
875
876 g_strfreev(pidlines);
877
878 return pids;
879}
880
881void SystemD::stopUnit(const AppID& appId, const std::string& job, const std::string& instance)
882{
883 auto registry = registry_.lock();
884 auto unitname = unitName(SystemD::UnitInfo{appId, job, instance});
885
886 registry->impl->thread.executeOnThread<bool>([this, registry, unitname] {
887 GError* error{nullptr};
888 GVariant* call = g_dbus_connection_call_sync(userbus_.get(), /* user bus */
889 SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */
890 SYSTEMD_DBUS_PATH_MANAGER.c_str(), /* path */
891 SYSTEMD_DBUS_IFACE_MANAGER.c_str(), /* interface */
892 "StopUnit", /* method */
893 g_variant_new("(ss)", unitname.c_str(), "fail"), /* params */
894 G_VARIANT_TYPE("(o)"), /* ret type */
895 G_DBUS_CALL_FLAGS_NONE, /* flags */
896 -1, /* timeout */
897 registry->impl->thread.getCancellable().get(), /* cancellable */
898 &error);
899
900 if (error != nullptr)
901 {
902 auto message =
903 std::string{"Unable to get SystemD to stop '"} + unitname + std::string{"': "} + error->message;
904 g_error_free(error);
905 throw std::runtime_error(message);
906 }
907
908 g_variant_unref(call);
909
910 return true;
911 });
912}
913
914core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& SystemD::appStarted()
915{
916 g_warning("Systemd signals not implemented");
917 return sig_appStarted;
918}
919
920core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& SystemD::appStopped()
921{
922 g_warning("Systemd signals not implemented");
923 return sig_appStopped;
924}
925
926core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>&
927 SystemD::appFailed()
928{
929 g_warning("Systemd signals not implemented");
930 return sig_appFailed;
931}
932
933core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
934 SystemD::appPaused()
935{
936 g_warning("Systemd signals not implemented");
937 return sig_appPaused;
938}
939
940core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
941 SystemD::appResumed()
942{
943 g_warning("Systemd signals not implemented");
944 return sig_appResumed;
945}
946
947} // namespace manager
948} // namespace jobs
949} // namespace app_launch
950} // namespace ubuntu
0951
=== added file 'libubuntu-app-launch/jobs-systemd.h'
--- libubuntu-app-launch/jobs-systemd.h 1970-01-01 00:00:00 +0000
+++ libubuntu-app-launch/jobs-systemd.h 2016-11-10 21:59:02 +0000
@@ -0,0 +1,123 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published
6 * by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranties of
10 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors:
17 * Ted Gould <ted.gould@canonical.com>
18 */
19
20#pragma once
21
22#include "jobs-base.h"
23#include <chrono>
24#include <gio/gio.h>
25#include <map>
26#include <mutex>
27
28namespace ubuntu
29{
30namespace app_launch
31{
32namespace jobs
33{
34namespace manager
35{
36
37class SystemD : public Base
38{
39public:
40 SystemD(std::shared_ptr<Registry> registry);
41 virtual ~SystemD();
42
43 virtual std::shared_ptr<Application::Instance> launch(
44 const AppID& appId,
45 const std::string& job,
46 const std::string& instance,
47 const std::vector<Application::URL>& urls,
48 launchMode mode,
49 std::function<std::list<std::pair<std::string, std::string>>(void)>& getenv) override;
50 virtual std::shared_ptr<Application::Instance> existing(const AppID& appId,
51 const std::string& job,
52 const std::string& instance,
53 const std::vector<Application::URL>& urls) override;
54
55 virtual std::list<std::shared_ptr<Application>> runningApps() override;
56
57 virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) override;
58
59 virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStarted() override;
60 virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStopped() override;
61 virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>&
62 appFailed() override;
63 virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
64 appPaused() override;
65 virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
66 appResumed() override;
67
68 static std::string userBusPath();
69
70 pid_t unitPrimaryPid(const AppID& appId, const std::string& job, const std::string& instance);
71 std::vector<pid_t> unitPids(const AppID& appId, const std::string& job, const std::string& instance);
72 void stopUnit(const AppID& appId, const std::string& job, const std::string& instance);
73
74private:
75 std::shared_ptr<GDBusConnection> userbus_;
76
77 /* ssssssouso */
78 struct UnitEntry
79 {
80 std::string id;
81 std::string description;
82 std::string loadState;
83 std::string activeState;
84 std::string subState;
85 std::string following;
86 std::string path;
87 std::uint32_t jobId;
88 std::string jobType;
89 std::string jobPath;
90 };
91 std::list<UnitEntry> listUnits();
92
93 struct UnitInfo
94 {
95 std::string appid;
96 std::string job;
97 std::string inst;
98 };
99 UnitInfo parseUnit(const std::string& unit);
100 std::string unitName(const UnitInfo& info);
101
102 struct UnitPath
103 {
104 std::string unitName;
105 std::string unitPath;
106 std::chrono::time_point<std::chrono::system_clock> timeStamp;
107 };
108 std::list<UnitPath> unitPaths_;
109 std::mutex unitPathsMutex_;
110 std::string unitPath(const std::string& unitName);
111
112 static std::string findEnv(const std::string& value, std::list<std::pair<std::string, std::string>>& env);
113 static void copyEnv(const std::string& envname, std::list<std::pair<std::string, std::string>>& env);
114 static void copyEnvByPrefix(const std::string& prefix, std::list<std::pair<std::string, std::string>>& env);
115
116 static std::vector<std::string> parseExec(std::list<std::pair<std::string, std::string>>& env);
117 static void application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data);
118};
119
120} // namespace manager
121} // namespace jobs
122} // namespace app_launch
123} // namespace ubuntu
0124
=== modified file 'libubuntu-app-launch/jobs-upstart.cpp'
--- libubuntu-app-launch/jobs-upstart.cpp 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/jobs-upstart.cpp 2016-11-10 21:59:02 +0000
@@ -73,8 +73,6 @@
73private:73private:
74 std::string upstartJobPath(const std::string& job);74 std::string upstartJobPath(const std::string& job);
75 std::string upstartName();75 std::string upstartName();
76
77 static std::shared_ptr<gchar*> urlsToStrv(const std::vector<Application::URL>& urls);
78};76};
7977
80/** Uses Upstart to get the primary PID of the instance using Upstart's78/** Uses Upstart to get the primary PID of the instance using Upstart's
@@ -306,29 +304,6 @@
306 g_debug("Creating a new Upstart for '%s' instance '%s'", std::string(appId).c_str(), instance.c_str());304 g_debug("Creating a new Upstart for '%s' instance '%s'", std::string(appId).c_str(), instance.c_str());
307}305}
308306
309/** Reformat a C++ vector of URLs into a C GStrv of strings
310
311 \param urls Vector of URLs to make into C strings
312*/
313std::shared_ptr<gchar*> Upstart::urlsToStrv(const std::vector<Application::URL>& urls)
314{
315 if (urls.empty())
316 {
317 return {};
318 }
319
320 auto array = g_array_new(TRUE, FALSE, sizeof(gchar*));
321
322 for (auto url : urls)
323 {
324 auto str = g_strdup(url.value().c_str());
325 g_debug("Converting URL: %s", str);
326 g_array_append_val(array, str);
327 }
328
329 return std::shared_ptr<gchar*>((gchar**)g_array_free(array, FALSE), g_strfreev);
330}
331
332/** Small helper that we can new/delete to work better with C stuff */307/** Small helper that we can new/delete to work better with C stuff */
333struct StartCHelper308struct StartCHelper
334{309{
335310
=== modified file 'libubuntu-app-launch/registry-impl.cpp'
--- libubuntu-app-launch/registry-impl.cpp 2016-11-10 21:59:01 +0000
+++ libubuntu-app-launch/registry-impl.cpp 2016-11-10 21:59:02 +0000
@@ -144,7 +144,7 @@
144 if (error != nullptr)144 if (error != nullptr)
145 {145 {
146 auto perror = std::shared_ptr<GError>(error, [](GError* error) { g_error_free(error); });146 auto perror = std::shared_ptr<GError>(error, [](GError* error) { g_error_free(error); });
147 g_critical("Error parsing manifest for package '%s': %s", package.c_str(), perror->message);147 g_debug("Error parsing manifest for package '%s': %s", package.c_str(), perror->message);
148 return std::shared_ptr<JsonObject>();148 return std::shared_ptr<JsonObject>();
149 }149 }
150150
151151
=== modified file 'libubuntu-app-launch/snapd-info.cpp'
--- libubuntu-app-launch/snapd-info.cpp 2016-10-03 23:54:08 +0000
+++ libubuntu-app-launch/snapd-info.cpp 2016-11-10 21:59:02 +0000
@@ -170,7 +170,7 @@
170 }170 }
171 catch (std::runtime_error &e)171 catch (std::runtime_error &e)
172 {172 {
173 g_warning("Unable to get snap information for '%s': %s", package.value().c_str(), e.what());173 g_debug("Unable to get snap information for '%s': %s", package.value().c_str(), e.what());
174 return {};174 return {};
175 }175 }
176}176}
177177
=== modified file 'tests/exec-util-test.cc'
--- tests/exec-util-test.cc 2016-09-15 17:13:04 +0000
+++ tests/exec-util-test.cc 2016-11-10 21:59:02 +0000
@@ -45,6 +45,7 @@
45 g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);45 g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);
46 g_setenv("UBUNTU_APP_LAUNCH_LIBERTINE_LAUNCH", "libertine-launch", TRUE);46 g_setenv("UBUNTU_APP_LAUNCH_LIBERTINE_LAUNCH", "libertine-launch", TRUE);
47 g_setenv("UBUNTU_APP_LAUNCH_SNAPD_SOCKET", "/this/should/not/exist", TRUE);47 g_setenv("UBUNTU_APP_LAUNCH_SNAPD_SOCKET", "/this/should/not/exist", TRUE);
48 g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
4849
49 service = dbus_test_service_new(NULL);50 service = dbus_test_service_new(NULL);
5051
@@ -184,12 +185,15 @@
184 EXPECT_STREQ("grep", value); }},185 EXPECT_STREQ("grep", value); }},
185 {"APP_ID", [](const gchar * value) {186 {"APP_ID", [](const gchar * value) {
186 EXPECT_STREQ("com.test.good_application_1.2.3", value); }},187 EXPECT_STREQ("com.test.good_application_1.2.3", value); }},
188 {"APP_EXEC_POLICY", [](const gchar * value) {
189 EXPECT_STREQ("com.test.good_application_1.2.3", value); }},
187 {"APP_LAUNCHER_PID", [](const gchar * value) {190 {"APP_LAUNCHER_PID", [](const gchar * value) {
188 EXPECT_EQ(getpid(), atoi(value)); }},191 EXPECT_EQ(getpid(), atoi(value)); }},
189 {"APP_DESKTOP_FILE_PATH", [](const gchar * value) {192 {"APP_DESKTOP_FILE_PATH", [](const gchar * value) {
190 EXPECT_STREQ(APP_DIR "/application.desktop", value); }},193 EXPECT_STREQ(APP_DIR "/application.desktop", value); }},
191 {"APP_XMIR_ENABLE", [](const gchar * value) {194 {"APP_XMIR_ENABLE", [](const gchar * value) {
192 EXPECT_STREQ("0", value); }},195 EXPECT_STREQ("0", value); }},
196 {"QML2_IMPORT_PATH", nocheck},
193 });197 });
194198
195#undef APP_DIR199#undef APP_DIR
@@ -267,10 +271,13 @@
267 {"APP_EXEC", nocheck},271 {"APP_EXEC", nocheck},
268 {"APP_ID", [](const gchar * value) {272 {"APP_ID", [](const gchar * value) {
269 EXPECT_STREQ("com.test.mir_mir_1", value); }},273 EXPECT_STREQ("com.test.mir_mir_1", value); }},
274 {"APP_EXEC_POLICY", [](const gchar * value) {
275 EXPECT_STREQ("com.test.mir_mir_1", value); }},
270 {"APP_LAUNCHER_PID", nocheck},276 {"APP_LAUNCHER_PID", nocheck},
271 {"APP_DESKTOP_FILE_PATH", nocheck},277 {"APP_DESKTOP_FILE_PATH", nocheck},
272 {"APP_XMIR_ENABLE", [](const gchar * value) {278 {"APP_XMIR_ENABLE", [](const gchar * value) {
273 EXPECT_STREQ("1", value); }},279 EXPECT_STREQ("1", value); }},
280 {"QML2_IMPORT_PATH", nocheck},
274 });281 });
275}282}
276283
@@ -289,10 +296,13 @@
289 {"APP_EXEC", nocheck},296 {"APP_EXEC", nocheck},
290 {"APP_ID", [](const gchar * value) {297 {"APP_ID", [](const gchar * value) {
291 EXPECT_STREQ("com.test.mir_nomir_1", value); }},298 EXPECT_STREQ("com.test.mir_nomir_1", value); }},
299 {"APP_EXEC_POLICY", [](const gchar * value) {
300 EXPECT_STREQ("com.test.mir_nomir_1", value); }},
292 {"APP_LAUNCHER_PID", nocheck},301 {"APP_LAUNCHER_PID", nocheck},
293 {"APP_DESKTOP_FILE_PATH", nocheck},302 {"APP_DESKTOP_FILE_PATH", nocheck},
294 {"APP_XMIR_ENABLE", [](const gchar * value) {303 {"APP_XMIR_ENABLE", [](const gchar * value) {
295 EXPECT_STREQ("0", value); }},304 EXPECT_STREQ("0", value); }},
305 {"QML2_IMPORT_PATH", nocheck},
296 });306 });
297}307}
298308
299309
=== modified file 'tests/libual-cpp-test.cc'
--- tests/libual-cpp-test.cc 2016-11-10 21:59:01 +0000
+++ tests/libual-cpp-test.cc 2016-11-10 21:59:02 +0000
@@ -149,6 +149,7 @@
149 g_setenv("UBUNTU_APP_LAUNCH_DISABLE_SNAPD_TIMEOUT", "You betcha!", TRUE);149 g_setenv("UBUNTU_APP_LAUNCH_DISABLE_SNAPD_TIMEOUT", "You betcha!", TRUE);
150 g_unlink(SNAPD_TEST_SOCKET);150 g_unlink(SNAPD_TEST_SOCKET);
151#endif151#endif
152 g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
152153
153 service = dbus_test_service_new(NULL);154 service = dbus_test_service_new(NULL);
154155
155156
=== modified file 'tests/libual-test.cc'
--- tests/libual-test.cc 2016-09-14 15:29:35 +0000
+++ tests/libual-test.cc 2016-11-10 21:59:02 +0000
@@ -90,6 +90,7 @@
90 g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);90 g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);
9191
92 g_setenv("UBUNTU_APP_LAUNCH_SNAPD_SOCKET", "/this/should/not/exist", TRUE);92 g_setenv("UBUNTU_APP_LAUNCH_SNAPD_SOCKET", "/this/should/not/exist", TRUE);
93 g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE);
9394
94 service = dbus_test_service_new(NULL);95 service = dbus_test_service_new(NULL);
9596
9697
=== modified file 'xmir-helper.c'
--- xmir-helper.c 2015-08-11 02:41:08 +0000
+++ xmir-helper.c 2016-11-10 21:59:02 +0000
@@ -86,6 +86,8 @@
86 NULL86 NULL
87 };87 };
8888
89 printf("Executing XMir on PID: %d", getpid());
90
89 return execv(xmir, xmirexec);91 return execv(xmir, xmirexec);
90 }92 }
9193

Subscribers

People subscribed via source and target branches