Merge lp:~ted/ubuntu-app-launch/jobs-systemd into lp:ubuntu-app-launch/16.10
- jobs-systemd
- Merge into trunk.16.10
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 |
Related bugs: |
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
Description of the change
- 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
1 | === modified file 'libubuntu-app-launch/CMakeLists.txt' | |||
2 | --- libubuntu-app-launch/CMakeLists.txt 2016-11-10 21:59:01 +0000 | |||
3 | +++ libubuntu-app-launch/CMakeLists.txt 2016-11-10 21:59:02 +0000 | |||
4 | @@ -17,6 +17,8 @@ | |||
5 | 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wpedantic") | 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wpedantic") |
6 | 18 | add_definitions ( -DOOM_HELPER="${pkglibexecdir}/oom-adjust-setuid-helper" -DDEMANGLER_PATH="${pkglibexecdir}/socket-demangler" ) | 18 | add_definitions ( -DOOM_HELPER="${pkglibexecdir}/oom-adjust-setuid-helper" -DDEMANGLER_PATH="${pkglibexecdir}/socket-demangler" ) |
7 | 19 | add_definitions ( -DLIBERTINE_LAUNCH="${CMAKE_INSTALL_FULL_BINDIR}/libertine-launch" ) | 19 | add_definitions ( -DLIBERTINE_LAUNCH="${CMAKE_INSTALL_FULL_BINDIR}/libertine-launch" ) |
8 | 20 | add_definitions ( -DG_LOG_DOMAIN="ubuntu-app-launch" ) | ||
9 | 21 | add_definitions ( -DUBUNTU_APP_LAUNCH_ARCH="${UBUNTU_APP_LAUNCH_ARCH}" ) | ||
10 | 20 | 22 | ||
11 | 21 | set(LAUNCHER_HEADERS | 23 | set(LAUNCHER_HEADERS |
12 | 22 | ubuntu-app-launch.h | 24 | ubuntu-app-launch.h |
13 | @@ -54,6 +56,8 @@ | |||
14 | 54 | glib-thread.cpp | 56 | glib-thread.cpp |
15 | 55 | jobs-base.h | 57 | jobs-base.h |
16 | 56 | jobs-base.cpp | 58 | jobs-base.cpp |
17 | 59 | jobs-systemd.h | ||
18 | 60 | jobs-systemd.cpp | ||
19 | 57 | jobs-upstart.h | 61 | jobs-upstart.h |
20 | 58 | jobs-upstart.cpp | 62 | jobs-upstart.cpp |
21 | 59 | ) | 63 | ) |
22 | 60 | 64 | ||
23 | === modified file 'libubuntu-app-launch/application-impl-base.cpp' | |||
24 | --- libubuntu-app-launch/application-impl-base.cpp 2016-11-10 21:59:01 +0000 | |||
25 | +++ libubuntu-app-launch/application-impl-base.cpp 2016-11-10 21:59:02 +0000 | |||
26 | @@ -95,6 +95,26 @@ | |||
27 | 95 | return retval; | 95 | return retval; |
28 | 96 | } | 96 | } |
29 | 97 | 97 | ||
30 | 98 | /** Generates an instance string based on the clock if we're a multi-instance | ||
31 | 99 | application. */ | ||
32 | 100 | std::string Base::getInstance(const std::shared_ptr<app_info::Desktop>& desktop) | ||
33 | 101 | { | ||
34 | 102 | if (!desktop) | ||
35 | 103 | { | ||
36 | 104 | g_warning("Invalid desktop file passed to getInstance"); | ||
37 | 105 | return {}; | ||
38 | 106 | } | ||
39 | 107 | |||
40 | 108 | if (desktop->singleInstance()) | ||
41 | 109 | { | ||
42 | 110 | return {}; | ||
43 | 111 | } | ||
44 | 112 | else | ||
45 | 113 | { | ||
46 | 114 | return std::to_string(g_get_real_time()); | ||
47 | 115 | } | ||
48 | 116 | } | ||
49 | 117 | |||
50 | 98 | } // namespace app_impls | 118 | } // namespace app_impls |
51 | 99 | } // namespace app_launch | 119 | } // namespace app_launch |
52 | 100 | } // namespace ubuntu | 120 | } // namespace ubuntu |
53 | 101 | 121 | ||
54 | === modified file 'libubuntu-app-launch/application-impl-base.h' | |||
55 | --- libubuntu-app-launch/application-impl-base.h 2016-11-10 21:59:01 +0000 | |||
56 | +++ libubuntu-app-launch/application-impl-base.h 2016-11-10 21:59:02 +0000 | |||
57 | @@ -17,6 +17,7 @@ | |||
58 | 17 | * Ted Gould <ted.gould@canonical.com> | 17 | * Ted Gould <ted.gould@canonical.com> |
59 | 18 | */ | 18 | */ |
60 | 19 | 19 | ||
61 | 20 | #include "application-info-desktop.h" | ||
62 | 20 | #include "application.h" | 21 | #include "application.h" |
63 | 21 | 22 | ||
64 | 22 | extern "C" { | 23 | extern "C" { |
65 | @@ -43,6 +44,8 @@ | |||
66 | 43 | 44 | ||
67 | 44 | bool hasInstances() override; | 45 | bool hasInstances() override; |
68 | 45 | 46 | ||
69 | 47 | std::string getInstance(const std::shared_ptr<app_info::Desktop>& desktop); | ||
70 | 48 | |||
71 | 46 | protected: | 49 | protected: |
72 | 47 | /** Pointer to the registry so we can ask it for things */ | 50 | /** Pointer to the registry so we can ask it for things */ |
73 | 48 | std::shared_ptr<Registry> _registry; | 51 | std::shared_ptr<Registry> _registry; |
74 | 49 | 52 | ||
75 | === modified file 'libubuntu-app-launch/application-impl-click.cpp' | |||
76 | --- libubuntu-app-launch/application-impl-click.cpp 2016-11-10 21:59:01 +0000 | |||
77 | +++ libubuntu-app-launch/application-impl-click.cpp 2016-11-10 21:59:02 +0000 | |||
78 | @@ -51,6 +51,8 @@ | |||
79 | 51 | std::tie(_keyfile, desktopPath_) = manifestAppDesktop(_manifest, appid.package, appid.appname, _clickDir); | 51 | std::tie(_keyfile, desktopPath_) = manifestAppDesktop(_manifest, appid.package, appid.appname, _clickDir); |
80 | 52 | if (!_keyfile) | 52 | if (!_keyfile) |
81 | 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)}; |
82 | 54 | |||
83 | 55 | g_debug("Application Click object for appid '%s'", std::string(appid).c_str()); | ||
84 | 54 | } | 56 | } |
85 | 55 | 57 | ||
86 | 56 | AppID Click::appId() | 58 | AppID Click::appId() |
87 | @@ -337,11 +339,15 @@ | |||
88 | 337 | retval.emplace_back(std::make_pair("APP_DIR", _clickDir)); | 339 | retval.emplace_back(std::make_pair("APP_DIR", _clickDir)); |
89 | 338 | retval.emplace_back(std::make_pair("APP_DESKTOP_FILE_PATH", desktopPath_)); | 340 | retval.emplace_back(std::make_pair("APP_DESKTOP_FILE_PATH", desktopPath_)); |
90 | 339 | 341 | ||
91 | 342 | retval.emplace_back(std::make_pair("QML2_IMPORT_PATH", _clickDir + "/lib/" + UBUNTU_APP_LAUNCH_ARCH + "/qml")); | ||
92 | 343 | |||
93 | 340 | info(); | 344 | info(); |
94 | 341 | 345 | ||
95 | 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")); |
96 | 343 | retval.emplace_back(std::make_pair("APP_EXEC", _info->execLine().value())); | 347 | retval.emplace_back(std::make_pair("APP_EXEC", _info->execLine().value())); |
97 | 344 | 348 | ||
98 | 349 | retval.emplace_back(std::make_pair("APP_EXEC_POLICY", std::string(appId()))); | ||
99 | 350 | |||
100 | 345 | return retval; | 351 | return retval; |
101 | 346 | } | 352 | } |
102 | 347 | 353 | ||
103 | 348 | 354 | ||
104 | === modified file 'libubuntu-app-launch/application-impl-legacy.cpp' | |||
105 | --- libubuntu-app-launch/application-impl-legacy.cpp 2016-11-10 21:59:01 +0000 | |||
106 | +++ libubuntu-app-launch/application-impl-legacy.cpp 2016-11-10 21:59:02 +0000 | |||
107 | @@ -74,6 +74,8 @@ | |||
108 | 74 | { | 74 | { |
109 | 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()}; |
110 | 76 | } | 76 | } |
111 | 77 | |||
112 | 78 | g_debug("Application Legacy object for app '%s'", appname.value().c_str()); | ||
113 | 77 | } | 79 | } |
114 | 78 | 80 | ||
115 | 79 | std::tuple<std::string, std::shared_ptr<GKeyFile>, std::string> keyfileForApp(const AppID::AppName& name) | 81 | std::tuple<std::string, std::shared_ptr<GKeyFile>, std::string> keyfileForApp(const AppID::AppName& name) |
116 | @@ -342,21 +344,6 @@ | |||
117 | 342 | return retval; | 344 | return retval; |
118 | 343 | } | 345 | } |
119 | 344 | 346 | ||
120 | 345 | /** Generates an instance string based on the clock if we're a multi-instance | ||
121 | 346 | application. */ | ||
122 | 347 | std::string Legacy::getInstance() | ||
123 | 348 | { | ||
124 | 349 | auto single = g_key_file_get_boolean(_keyfile.get(), "Desktop Entry", "X-Ubuntu-Single-Instance", nullptr); | ||
125 | 350 | if (single) | ||
126 | 351 | { | ||
127 | 352 | return {}; | ||
128 | 353 | } | ||
129 | 354 | else | ||
130 | 355 | { | ||
131 | 356 | return std::to_string(g_get_real_time()); | ||
132 | 357 | } | ||
133 | 358 | } | ||
134 | 359 | |||
135 | 360 | /** Create an UpstartInstance for this AppID using the UpstartInstance launch | 347 | /** Create an UpstartInstance for this AppID using the UpstartInstance launch |
136 | 361 | function. | 348 | function. |
137 | 362 | 349 | ||
138 | @@ -364,7 +351,7 @@ | |||
139 | 364 | */ | 351 | */ |
140 | 365 | std::shared_ptr<Application::Instance> Legacy::launch(const std::vector<Application::URL>& urls) | 352 | std::shared_ptr<Application::Instance> Legacy::launch(const std::vector<Application::URL>& urls) |
141 | 366 | { | 353 | { |
143 | 367 | std::string instance = getInstance(); | 354 | auto instance = getInstance(appinfo_); |
144 | 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]() { |
145 | 369 | return launchEnv(instance); | 356 | return launchEnv(instance); |
146 | 370 | }; | 357 | }; |
147 | @@ -379,7 +366,7 @@ | |||
148 | 379 | */ | 366 | */ |
149 | 380 | std::shared_ptr<Application::Instance> Legacy::launchTest(const std::vector<Application::URL>& urls) | 367 | std::shared_ptr<Application::Instance> Legacy::launchTest(const std::vector<Application::URL>& urls) |
150 | 381 | { | 368 | { |
152 | 382 | std::string instance = getInstance(); | 369 | auto instance = getInstance(appinfo_); |
153 | 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]() { |
154 | 384 | return launchEnv(instance); | 371 | return launchEnv(instance); |
155 | 385 | }; | 372 | }; |
156 | 386 | 373 | ||
157 | === modified file 'libubuntu-app-launch/application-impl-legacy.h' | |||
158 | --- libubuntu-app-launch/application-impl-legacy.h 2016-09-23 21:54:33 +0000 | |||
159 | +++ libubuntu-app-launch/application-impl-legacy.h 2016-11-10 21:59:02 +0000 | |||
160 | @@ -86,7 +86,6 @@ | |||
161 | 86 | std::regex instanceRegex_; | 86 | std::regex instanceRegex_; |
162 | 87 | 87 | ||
163 | 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); |
164 | 89 | std::string getInstance(); | ||
165 | 90 | }; | 89 | }; |
166 | 91 | 90 | ||
167 | 92 | } // namespace app_impls | 91 | } // namespace app_impls |
168 | 93 | 92 | ||
169 | === modified file 'libubuntu-app-launch/application-impl-libertine.cpp' | |||
170 | --- libubuntu-app-launch/application-impl-libertine.cpp 2016-11-10 21:59:01 +0000 | |||
171 | +++ libubuntu-app-launch/application-impl-libertine.cpp 2016-11-10 21:59:02 +0000 | |||
172 | @@ -65,6 +65,12 @@ | |||
173 | 65 | if (!_keyfile) | 65 | if (!_keyfile) |
174 | 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 '" + |
175 | 67 | container.value() + "'"}; | 67 | container.value() + "'"}; |
176 | 68 | |||
177 | 69 | appinfo_ = std::make_shared<app_info::Desktop>(_keyfile, _basedir, _container_path, | ||
178 | 70 | app_info::DesktopFlags::XMIR_DEFAULT, _registry); | ||
179 | 71 | |||
180 | 72 | g_debug("Application Libertine object for container '%s' app '%s'", container.value().c_str(), | ||
181 | 73 | appname.value().c_str()); | ||
182 | 68 | } | 74 | } |
183 | 69 | 75 | ||
184 | 70 | std::shared_ptr<GKeyFile> Libertine::keyfileFromPath(const std::string& pathname) | 76 | std::shared_ptr<GKeyFile> Libertine::keyfileFromPath(const std::string& pathname) |
185 | @@ -265,11 +271,6 @@ | |||
186 | 265 | 271 | ||
187 | 266 | std::shared_ptr<Application::Info> Libertine::info() | 272 | std::shared_ptr<Application::Info> Libertine::info() |
188 | 267 | { | 273 | { |
189 | 268 | if (!appinfo_) | ||
190 | 269 | { | ||
191 | 270 | appinfo_ = std::make_shared<app_info::Desktop>(_keyfile, _basedir, _container_path, | ||
192 | 271 | app_info::DesktopFlags::XMIR_DEFAULT, _registry); | ||
193 | 272 | } | ||
194 | 273 | return appinfo_; | 274 | return appinfo_; |
195 | 274 | } | 275 | } |
196 | 275 | 276 | ||
197 | @@ -317,15 +318,17 @@ | |||
198 | 317 | 318 | ||
199 | 318 | std::shared_ptr<Application::Instance> Libertine::launch(const std::vector<Application::URL>& urls) | 319 | std::shared_ptr<Application::Instance> Libertine::launch(const std::vector<Application::URL>& urls) |
200 | 319 | { | 320 | { |
201 | 321 | auto instance = getInstance(appinfo_); | ||
202 | 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(); }; |
205 | 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, |
206 | 322 | envfunc); | 324 | jobs::manager::launchMode::STANDARD, envfunc); |
207 | 323 | } | 325 | } |
208 | 324 | 326 | ||
209 | 325 | std::shared_ptr<Application::Instance> Libertine::launchTest(const std::vector<Application::URL>& urls) | 327 | std::shared_ptr<Application::Instance> Libertine::launchTest(const std::vector<Application::URL>& urls) |
210 | 326 | { | 328 | { |
211 | 329 | auto instance = getInstance(appinfo_); | ||
212 | 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(); }; |
214 | 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, |
215 | 329 | envfunc); | 332 | envfunc); |
216 | 330 | } | 333 | } |
217 | 331 | 334 | ||
218 | 332 | 335 | ||
219 | === modified file 'libubuntu-app-launch/application-impl-snap.cpp' | |||
220 | --- libubuntu-app-launch/application-impl-snap.cpp 2016-11-10 21:59:01 +0000 | |||
221 | +++ libubuntu-app-launch/application-impl-snap.cpp 2016-11-10 21:59:02 +0000 | |||
222 | @@ -196,6 +196,8 @@ | |||
223 | 196 | } | 196 | } |
224 | 197 | 197 | ||
225 | 198 | info_ = std::make_shared<SnapInfo>(appid_, _registry, interface_, pkgInfo_->directory); | 198 | info_ = std::make_shared<SnapInfo>(appid_, _registry, interface_, pkgInfo_->directory); |
226 | 199 | |||
227 | 200 | g_debug("Application Snap object for AppID '%s'", std::string(appid).c_str()); | ||
228 | 199 | } | 201 | } |
229 | 200 | 202 | ||
230 | 201 | /** Uses the findInterface() function to find the interface if we don't | 203 | /** Uses the findInterface() function to find the interface if we don't |
231 | @@ -229,7 +231,7 @@ | |||
232 | 229 | } | 231 | } |
233 | 230 | catch (std::runtime_error& e) | 232 | catch (std::runtime_error& e) |
234 | 231 | { | 233 | { |
236 | 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()); |
237 | 233 | } | 235 | } |
238 | 234 | } | 236 | } |
239 | 235 | } | 237 | } |
240 | @@ -436,9 +438,10 @@ | |||
241 | 436 | */ | 438 | */ |
242 | 437 | std::shared_ptr<Application::Instance> Snap::launch(const std::vector<Application::URL>& urls) | 439 | std::shared_ptr<Application::Instance> Snap::launch(const std::vector<Application::URL>& urls) |
243 | 438 | { | 440 | { |
244 | 441 | auto instance = getInstance(info_); | ||
245 | 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(); }; |
248 | 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, |
249 | 441 | envfunc); | 444 | jobs::manager::launchMode::STANDARD, envfunc); |
250 | 442 | } | 445 | } |
251 | 443 | 446 | ||
252 | 444 | /** Create a new instance of this Snap with a testing environment | 447 | /** Create a new instance of this Snap with a testing environment |
253 | @@ -448,8 +451,9 @@ | |||
254 | 448 | */ | 451 | */ |
255 | 449 | std::shared_ptr<Application::Instance> Snap::launchTest(const std::vector<Application::URL>& urls) | 452 | std::shared_ptr<Application::Instance> Snap::launchTest(const std::vector<Application::URL>& urls) |
256 | 450 | { | 453 | { |
257 | 454 | auto instance = getInstance(info_); | ||
258 | 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(); }; |
260 | 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, |
261 | 453 | envfunc); | 457 | envfunc); |
262 | 454 | } | 458 | } |
263 | 455 | 459 | ||
264 | 456 | 460 | ||
265 | === modified file 'libubuntu-app-launch/application-info-desktop.cpp' | |||
266 | --- libubuntu-app-launch/application-info-desktop.cpp 2016-09-14 16:42:20 +0000 | |||
267 | +++ libubuntu-app-launch/application-info-desktop.cpp 2016-11-10 21:59:02 +0000 | |||
268 | @@ -253,7 +253,7 @@ | |||
269 | 253 | if (stringlistFromKeyfileContains(keyfile, "NotShowIn", xdg_current_desktop, false) || | 253 | if (stringlistFromKeyfileContains(keyfile, "NotShowIn", xdg_current_desktop, false) || |
270 | 254 | !stringlistFromKeyfileContains(keyfile, "OnlyShowIn", xdg_current_desktop, true)) | 254 | !stringlistFromKeyfileContains(keyfile, "OnlyShowIn", xdg_current_desktop, true)) |
271 | 255 | { | 255 | { |
273 | 256 | g_warning("Application is not shown in Unity"); | 256 | g_debug("Application is not shown in current desktop: %s", xdg_current_desktop); |
274 | 257 | // Exception removed for OTA11 as a temporary fix | 257 | // Exception removed for OTA11 as a temporary fix |
275 | 258 | // throw std::runtime_error("Application is not shown in Unity"); | 258 | // throw std::runtime_error("Application is not shown in Unity"); |
276 | 259 | } | 259 | } |
277 | @@ -352,6 +352,7 @@ | |||
278 | 352 | , _xMirEnable( | 352 | , _xMirEnable( |
279 | 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())) |
280 | 354 | , _exec(stringFromKeyfile<Exec>(keyfile, "Exec")) | 354 | , _exec(stringFromKeyfile<Exec>(keyfile, "Exec")) |
281 | 355 | , _singleInstance(boolFromKeyfile<SingleInstance>(keyfile, "X-Ubuntu-Single-Instance", false)) | ||
282 | 355 | { | 356 | { |
283 | 356 | } | 357 | } |
284 | 357 | 358 | ||
285 | 358 | 359 | ||
286 | === modified file 'libubuntu-app-launch/application-info-desktop.h' | |||
287 | --- libubuntu-app-launch/application-info-desktop.h 2016-09-14 16:38:42 +0000 | |||
288 | +++ libubuntu-app-launch/application-info-desktop.h 2016-11-10 21:59:02 +0000 | |||
289 | @@ -106,6 +106,13 @@ | |||
290 | 106 | return _exec; | 106 | return _exec; |
291 | 107 | } | 107 | } |
292 | 108 | 108 | ||
293 | 109 | struct SingleInstanceTag; | ||
294 | 110 | typedef TypeTagger<SingleInstanceTag, bool> SingleInstance; | ||
295 | 111 | virtual SingleInstance singleInstance() | ||
296 | 112 | { | ||
297 | 113 | return _singleInstance; | ||
298 | 114 | } | ||
299 | 115 | |||
300 | 109 | protected: | 116 | protected: |
301 | 110 | std::shared_ptr<GKeyFile> _keyfile; | 117 | std::shared_ptr<GKeyFile> _keyfile; |
302 | 111 | std::string _basePath; | 118 | std::string _basePath; |
303 | @@ -125,6 +132,7 @@ | |||
304 | 125 | 132 | ||
305 | 126 | XMirEnable _xMirEnable; | 133 | XMirEnable _xMirEnable; |
306 | 127 | Exec _exec; | 134 | Exec _exec; |
307 | 135 | SingleInstance _singleInstance; | ||
308 | 128 | }; | 136 | }; |
309 | 129 | 137 | ||
310 | 130 | } // namespace AppInfo | 138 | } // namespace AppInfo |
311 | 131 | 139 | ||
312 | === modified file 'libubuntu-app-launch/jobs-base.cpp' | |||
313 | --- libubuntu-app-launch/jobs-base.cpp 2016-11-10 21:59:01 +0000 | |||
314 | +++ libubuntu-app-launch/jobs-base.cpp 2016-11-10 21:59:02 +0000 | |||
315 | @@ -23,6 +23,7 @@ | |||
316 | 23 | #include <numeric> | 23 | #include <numeric> |
317 | 24 | 24 | ||
318 | 25 | #include "jobs-base.h" | 25 | #include "jobs-base.h" |
319 | 26 | #include "jobs-systemd.h" | ||
320 | 26 | #include "jobs-upstart.h" | 27 | #include "jobs-upstart.h" |
321 | 27 | #include "registry-impl.h" | 28 | #include "registry-impl.h" |
322 | 28 | 29 | ||
323 | @@ -37,6 +38,7 @@ | |||
324 | 37 | 38 | ||
325 | 38 | Base::Base(const std::shared_ptr<Registry>& registry) | 39 | Base::Base(const std::shared_ptr<Registry>& registry) |
326 | 39 | : registry_(registry) | 40 | : registry_(registry) |
327 | 41 | , allJobs_{"application-click", "application-legacy", "application-snap"} | ||
328 | 40 | , dbus_(registry->impl->_dbus) | 42 | , dbus_(registry->impl->_dbus) |
329 | 41 | { | 43 | { |
330 | 42 | } | 44 | } |
331 | @@ -58,7 +60,23 @@ | |||
332 | 58 | 60 | ||
333 | 59 | std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry) | 61 | std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry) |
334 | 60 | { | 62 | { |
336 | 61 | return std::make_shared<jobs::manager::Upstart>(registry); | 63 | /* Checking to see if we have a user bus, that is only started |
337 | 64 | by systemd so we're in good shape if we have one. We're using | ||
338 | 65 | the path instead of the RUNTIME variable because we want to work | ||
339 | 66 | around the case of being relocated by the snappy environment */ | ||
340 | 67 | if (g_file_test(SystemD::userBusPath().c_str(), G_FILE_TEST_EXISTS)) | ||
341 | 68 | { | ||
342 | 69 | return std::make_shared<jobs::manager::SystemD>(registry); | ||
343 | 70 | } | ||
344 | 71 | else | ||
345 | 72 | { | ||
346 | 73 | return std::make_shared<jobs::manager::Upstart>(registry); | ||
347 | 74 | } | ||
348 | 75 | } | ||
349 | 76 | |||
350 | 77 | const std::set<std::string>& Base::getAllJobs() | ||
351 | 78 | { | ||
352 | 79 | return allJobs_; | ||
353 | 62 | } | 80 | } |
354 | 63 | 81 | ||
355 | 64 | /** Take the GVariant of parameters and turn them into an application and | 82 | /** Take the GVariant of parameters and turn them into an application and |
356 | @@ -277,7 +295,9 @@ | |||
357 | 277 | bool Base::hasPid(pid_t pid) | 295 | bool Base::hasPid(pid_t pid) |
358 | 278 | { | 296 | { |
359 | 279 | auto vpids = pids(); | 297 | auto vpids = pids(); |
361 | 280 | return std::find(vpids.begin(), vpids.end(), pid) != vpids.end(); | 298 | bool hasit = std::find(vpids.begin(), vpids.end(), pid) != vpids.end(); |
362 | 299 | g_debug("Checking for PID %d on AppID '%s' result: %s", pid, std::string(appId_).c_str(), hasit ? "YES" : "NO"); | ||
363 | 300 | return hasit; | ||
364 | 281 | } | 301 | } |
365 | 282 | 302 | ||
366 | 283 | /** Pauses this application by sending SIGSTOP to all the PIDs in the | 303 | /** Pauses this application by sending SIGSTOP to all the PIDs in the |
367 | @@ -585,6 +605,29 @@ | |||
368 | 585 | } | 605 | } |
369 | 586 | } | 606 | } |
370 | 587 | 607 | ||
371 | 608 | /** Reformat a C++ vector of URLs into a C GStrv of strings | ||
372 | 609 | |||
373 | 610 | \param urls Vector of URLs to make into C strings | ||
374 | 611 | */ | ||
375 | 612 | std::shared_ptr<gchar*> Base::urlsToStrv(const std::vector<Application::URL>& urls) | ||
376 | 613 | { | ||
377 | 614 | if (urls.empty()) | ||
378 | 615 | { | ||
379 | 616 | return {}; | ||
380 | 617 | } | ||
381 | 618 | |||
382 | 619 | auto array = g_array_new(TRUE, FALSE, sizeof(gchar*)); | ||
383 | 620 | |||
384 | 621 | for (auto url : urls) | ||
385 | 622 | { | ||
386 | 623 | auto str = g_strdup(url.value().c_str()); | ||
387 | 624 | g_debug("Converting URL: %s", str); | ||
388 | 625 | g_array_append_val(array, str); | ||
389 | 626 | } | ||
390 | 627 | |||
391 | 628 | return std::shared_ptr<gchar*>((gchar**)g_array_free(array, FALSE), g_strfreev); | ||
392 | 629 | } | ||
393 | 630 | |||
394 | 588 | } // namespace instance | 631 | } // namespace instance |
395 | 589 | 632 | ||
396 | 590 | } // namespace jobs | 633 | } // namespace jobs |
397 | 591 | 634 | ||
398 | === modified file 'libubuntu-app-launch/jobs-base.h' | |||
399 | --- libubuntu-app-launch/jobs-base.h 2016-11-10 21:59:01 +0000 | |||
400 | +++ libubuntu-app-launch/jobs-base.h 2016-11-10 21:59:02 +0000 | |||
401 | @@ -24,6 +24,7 @@ | |||
402 | 24 | 24 | ||
403 | 25 | #include <core/signal.h> | 25 | #include <core/signal.h> |
404 | 26 | #include <gio/gio.h> | 26 | #include <gio/gio.h> |
405 | 27 | #include <set> | ||
406 | 27 | 28 | ||
407 | 28 | namespace ubuntu | 29 | namespace ubuntu |
408 | 29 | { | 30 | { |
409 | @@ -66,6 +67,8 @@ | |||
410 | 66 | /** A link to the registry we're using for connections */ | 67 | /** A link to the registry we're using for connections */ |
411 | 67 | std::shared_ptr<Registry> registry_; | 68 | std::shared_ptr<Registry> registry_; |
412 | 68 | 69 | ||
413 | 70 | static std::shared_ptr<gchar*> urlsToStrv(const std::vector<Application::URL>& urls); | ||
414 | 71 | |||
415 | 69 | private: | 72 | private: |
416 | 70 | std::vector<pid_t> forAllPids(std::function<void(pid_t)> eachPid); | 73 | std::vector<pid_t> forAllPids(std::function<void(pid_t)> eachPid); |
417 | 71 | void signalToPid(pid_t pid, int signal); | 74 | void signalToPid(pid_t pid, int signal); |
418 | @@ -110,6 +113,8 @@ | |||
419 | 110 | 113 | ||
420 | 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; |
421 | 112 | 115 | ||
422 | 116 | const std::set<std::string>& getAllJobs(); | ||
423 | 117 | |||
424 | 113 | static std::shared_ptr<Base> determineFactory(std::shared_ptr<Registry> registry); | 118 | static std::shared_ptr<Base> determineFactory(std::shared_ptr<Registry> registry); |
425 | 114 | 119 | ||
426 | 115 | /* Signals to apps */ | 120 | /* Signals to apps */ |
427 | @@ -130,6 +135,9 @@ | |||
428 | 130 | /** A link to the registry */ | 135 | /** A link to the registry */ |
429 | 131 | std::weak_ptr<Registry> registry_; | 136 | std::weak_ptr<Registry> registry_; |
430 | 132 | 137 | ||
431 | 138 | /** A set of all the job names */ | ||
432 | 139 | std::set<std::string> allJobs_; | ||
433 | 140 | |||
434 | 133 | /** The DBus connection we're connecting to */ | 141 | /** The DBus connection we're connecting to */ |
435 | 134 | std::shared_ptr<GDBusConnection> dbus_; | 142 | std::shared_ptr<GDBusConnection> dbus_; |
436 | 135 | 143 | ||
437 | 136 | 144 | ||
438 | === added file 'libubuntu-app-launch/jobs-systemd.cpp' | |||
439 | --- libubuntu-app-launch/jobs-systemd.cpp 1970-01-01 00:00:00 +0000 | |||
440 | +++ libubuntu-app-launch/jobs-systemd.cpp 2016-11-10 21:59:02 +0000 | |||
441 | @@ -0,0 +1,950 @@ | |||
442 | 1 | /* | ||
443 | 2 | * Copyright © 2016 Canonical Ltd. | ||
444 | 3 | * | ||
445 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
446 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
447 | 6 | * by the Free Software Foundation. | ||
448 | 7 | * | ||
449 | 8 | * This program is distributed in the hope that it will be useful, but | ||
450 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
451 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
452 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
453 | 12 | * | ||
454 | 13 | * You should have received a copy of the GNU General Public License along | ||
455 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
456 | 15 | * | ||
457 | 16 | * Authors: | ||
458 | 17 | * Ted Gould <ted.gould@canonical.com> | ||
459 | 18 | */ | ||
460 | 19 | |||
461 | 20 | #include <algorithm> | ||
462 | 21 | #include <gio/gio.h> | ||
463 | 22 | #include <numeric> | ||
464 | 23 | #include <regex> | ||
465 | 24 | #include <sys/types.h> | ||
466 | 25 | #include <unistd.h> | ||
467 | 26 | |||
468 | 27 | #include "helpers.h" | ||
469 | 28 | #include "jobs-systemd.h" | ||
470 | 29 | #include "registry-impl.h" | ||
471 | 30 | #include "second-exec-core.h" | ||
472 | 31 | |||
473 | 32 | extern "C" { | ||
474 | 33 | #include "ubuntu-app-launch-trace.h" | ||
475 | 34 | } | ||
476 | 35 | |||
477 | 36 | namespace ubuntu | ||
478 | 37 | { | ||
479 | 38 | namespace app_launch | ||
480 | 39 | { | ||
481 | 40 | namespace jobs | ||
482 | 41 | { | ||
483 | 42 | namespace instance | ||
484 | 43 | { | ||
485 | 44 | |||
486 | 45 | class SystemD : public Base | ||
487 | 46 | { | ||
488 | 47 | friend class manager::SystemD; | ||
489 | 48 | |||
490 | 49 | public: | ||
491 | 50 | explicit SystemD(const AppID& appId, | ||
492 | 51 | const std::string& job, | ||
493 | 52 | const std::string& instance, | ||
494 | 53 | const std::vector<Application::URL>& urls, | ||
495 | 54 | const std::shared_ptr<Registry>& registry); | ||
496 | 55 | |||
497 | 56 | /* Query lifecycle */ | ||
498 | 57 | pid_t primaryPid() override; | ||
499 | 58 | std::string logPath() override; | ||
500 | 59 | std::vector<pid_t> pids() override; | ||
501 | 60 | |||
502 | 61 | /* Manage lifecycle */ | ||
503 | 62 | void stop() override; | ||
504 | 63 | |||
505 | 64 | }; // class SystemD | ||
506 | 65 | |||
507 | 66 | SystemD::SystemD(const AppID& appId, | ||
508 | 67 | const std::string& job, | ||
509 | 68 | const std::string& instance, | ||
510 | 69 | const std::vector<Application::URL>& urls, | ||
511 | 70 | const std::shared_ptr<Registry>& registry) | ||
512 | 71 | : Base(appId, job, instance, urls, registry) | ||
513 | 72 | { | ||
514 | 73 | g_debug("Creating a new SystemD for '%s' instance '%s'", std::string(appId).c_str(), instance.c_str()); | ||
515 | 74 | } | ||
516 | 75 | |||
517 | 76 | pid_t SystemD::primaryPid() | ||
518 | 77 | { | ||
519 | 78 | auto manager = std::dynamic_pointer_cast<manager::SystemD>(registry_->impl->jobs); | ||
520 | 79 | return manager->unitPrimaryPid(appId_, job_, instance_); | ||
521 | 80 | } | ||
522 | 81 | |||
523 | 82 | std::string SystemD::logPath() | ||
524 | 83 | { | ||
525 | 84 | /* NOTE: We can never get this for systemd */ | ||
526 | 85 | return {}; | ||
527 | 86 | } | ||
528 | 87 | |||
529 | 88 | std::vector<pid_t> SystemD::pids() | ||
530 | 89 | { | ||
531 | 90 | auto manager = std::dynamic_pointer_cast<manager::SystemD>(registry_->impl->jobs); | ||
532 | 91 | return manager->unitPids(appId_, job_, instance_); | ||
533 | 92 | } | ||
534 | 93 | |||
535 | 94 | void SystemD::stop() | ||
536 | 95 | { | ||
537 | 96 | auto manager = std::dynamic_pointer_cast<manager::SystemD>(registry_->impl->jobs); | ||
538 | 97 | return manager->stopUnit(appId_, job_, instance_); | ||
539 | 98 | } | ||
540 | 99 | |||
541 | 100 | } // namespace instance | ||
542 | 101 | |||
543 | 102 | namespace manager | ||
544 | 103 | { | ||
545 | 104 | |||
546 | 105 | static const std::string SYSTEMD_DBUS_ADDRESS{"org.freedesktop.systemd1"}; | ||
547 | 106 | static const std::string SYSTEMD_DBUS_IFACE_MANAGER{"org.freedesktop.systemd1.Manager"}; | ||
548 | 107 | static const std::string SYSTEMD_DBUS_PATH_MANAGER{"/org/freedesktop/systemd1"}; | ||
549 | 108 | static const std::string SYSTEMD_DBUS_IFACE_UNIT{"org.freedesktop.systemd1.Unit"}; | ||
550 | 109 | static const std::string SYSTEMD_DBUS_IFACE_SERVICE{"org.freedesktop.systemd1.Service"}; | ||
551 | 110 | |||
552 | 111 | SystemD::SystemD(std::shared_ptr<Registry> registry) | ||
553 | 112 | : Base(registry) | ||
554 | 113 | { | ||
555 | 114 | auto cancel = registry->impl->thread.getCancellable(); | ||
556 | 115 | userbus_ = registry->impl->thread.executeOnThread<std::shared_ptr<GDBusConnection>>([cancel]() { | ||
557 | 116 | GError* error = nullptr; | ||
558 | 117 | auto bus = std::shared_ptr<GDBusConnection>( | ||
559 | 118 | g_dbus_connection_new_for_address_sync( | ||
560 | 119 | ("unix:path=" + userBusPath()).c_str(), /* path to the user bus */ | ||
561 | 120 | (GDBusConnectionFlags)(G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | | ||
562 | 121 | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION), /* It is a message bus */ | ||
563 | 122 | nullptr, /* observer */ | ||
564 | 123 | cancel.get(), /* cancellable from the thread */ | ||
565 | 124 | &error), /* error */ | ||
566 | 125 | [](GDBusConnection* bus) { g_clear_object(&bus); }); | ||
567 | 126 | |||
568 | 127 | if (error != nullptr) | ||
569 | 128 | { | ||
570 | 129 | std::string message = std::string("Unable to connect to user bus: ") + error->message; | ||
571 | 130 | g_error_free(error); | ||
572 | 131 | throw std::runtime_error(message); | ||
573 | 132 | } | ||
574 | 133 | |||
575 | 134 | return bus; | ||
576 | 135 | }); | ||
577 | 136 | } | ||
578 | 137 | |||
579 | 138 | SystemD::~SystemD() | ||
580 | 139 | { | ||
581 | 140 | } | ||
582 | 141 | |||
583 | 142 | std::string SystemD::findEnv(const std::string& value, std::list<std::pair<std::string, std::string>>& env) | ||
584 | 143 | { | ||
585 | 144 | std::string retval; | ||
586 | 145 | auto entry = std::find_if(env.begin(), env.end(), | ||
587 | 146 | [&value](std::pair<std::string, std::string>& entry) { return entry.first == value; }); | ||
588 | 147 | |||
589 | 148 | if (entry != env.end()) | ||
590 | 149 | { | ||
591 | 150 | retval = entry->second; | ||
592 | 151 | } | ||
593 | 152 | |||
594 | 153 | return retval; | ||
595 | 154 | } | ||
596 | 155 | |||
597 | 156 | std::vector<std::string> SystemD::parseExec(std::list<std::pair<std::string, std::string>>& env) | ||
598 | 157 | { | ||
599 | 158 | auto exec = findEnv("APP_EXEC", env); | ||
600 | 159 | if (exec.empty()) | ||
601 | 160 | { | ||
602 | 161 | g_debug("Application exec line is empty?!?!?"); | ||
603 | 162 | return {}; | ||
604 | 163 | } | ||
605 | 164 | auto uris = findEnv("APP_URIS", env); | ||
606 | 165 | |||
607 | 166 | auto execarray = desktop_exec_parse(exec.c_str(), uris.c_str()); | ||
608 | 167 | |||
609 | 168 | std::vector<std::string> retval; | ||
610 | 169 | retval.reserve(execarray->len); | ||
611 | 170 | for (unsigned int i = 0; i < execarray->len; i++) | ||
612 | 171 | { | ||
613 | 172 | retval.emplace_back(g_array_index(execarray, gchar*, i)); | ||
614 | 173 | } | ||
615 | 174 | |||
616 | 175 | g_array_set_clear_func(execarray, g_free); | ||
617 | 176 | g_array_free(execarray, FALSE); /* TODO: Not TRUE? */ | ||
618 | 177 | |||
619 | 178 | /* See if we need the xmir helper */ | ||
620 | 179 | if (findEnv("APP_XMIR_ENABLE", env) == "1" && getenv("DISPLAY") == nullptr) | ||
621 | 180 | { | ||
622 | 181 | retval.emplace(retval.begin(), findEnv("APP_ID", env)); | ||
623 | 182 | retval.emplace(retval.begin(), XMIR_HELPER); | ||
624 | 183 | } | ||
625 | 184 | |||
626 | 185 | /* See if we're doing apparmor by hand */ | ||
627 | 186 | auto appexecpolicy = findEnv("APP_EXEC_POLICY", env); | ||
628 | 187 | if (!appexecpolicy.empty() && appexecpolicy != "unconfined") | ||
629 | 188 | { | ||
630 | 189 | retval.emplace(retval.begin(), appexecpolicy); | ||
631 | 190 | retval.emplace(retval.begin(), "-p"); | ||
632 | 191 | retval.emplace(retval.begin(), "aa-exec"); | ||
633 | 192 | } | ||
634 | 193 | |||
635 | 194 | return retval; | ||
636 | 195 | } | ||
637 | 196 | |||
638 | 197 | /** Small helper that we can new/delete to work better with C stuff */ | ||
639 | 198 | struct StartCHelper | ||
640 | 199 | { | ||
641 | 200 | std::shared_ptr<instance::SystemD> ptr; | ||
642 | 201 | std::shared_ptr<GDBusConnection> bus; | ||
643 | 202 | }; | ||
644 | 203 | |||
645 | 204 | void SystemD::application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data) | ||
646 | 205 | { | ||
647 | 206 | auto data = static_cast<StartCHelper*>(user_data); | ||
648 | 207 | GError* error{nullptr}; | ||
649 | 208 | GVariant* result{nullptr}; | ||
650 | 209 | |||
651 | 210 | tracepoint(ubuntu_app_launch, libual_start_message_callback, std::string(data->ptr->appId_).c_str()); | ||
652 | 211 | |||
653 | 212 | g_debug("Started Message Callback: %s", std::string(data->ptr->appId_).c_str()); | ||
654 | 213 | |||
655 | 214 | result = g_dbus_connection_call_finish(G_DBUS_CONNECTION(obj), res, &error); | ||
656 | 215 | |||
657 | 216 | g_clear_pointer(&result, g_variant_unref); | ||
658 | 217 | |||
659 | 218 | if (error != nullptr) | ||
660 | 219 | { | ||
661 | 220 | if (g_dbus_error_is_remote_error(error)) | ||
662 | 221 | { | ||
663 | 222 | gchar* remote_error = g_dbus_error_get_remote_error(error); | ||
664 | 223 | g_debug("Remote error: %s", remote_error); | ||
665 | 224 | if (g_strcmp0(remote_error, "org.freedesktop.systemd1.UnitExists") == 0) | ||
666 | 225 | { | ||
667 | 226 | auto urls = instance::SystemD::urlsToStrv(data->ptr->urls_); | ||
668 | 227 | second_exec(data->bus.get(), /* DBus */ | ||
669 | 228 | data->ptr->registry_->impl->thread.getCancellable().get(), /* cancellable */ | ||
670 | 229 | data->ptr->primaryPid(), /* primary pid */ | ||
671 | 230 | std::string(data->ptr->appId_).c_str(), /* appid */ | ||
672 | 231 | urls.get()); /* urls */ | ||
673 | 232 | } | ||
674 | 233 | |||
675 | 234 | g_free(remote_error); | ||
676 | 235 | } | ||
677 | 236 | else | ||
678 | 237 | { | ||
679 | 238 | g_warning("Unable to emit event to start application: %s", error->message); | ||
680 | 239 | } | ||
681 | 240 | g_error_free(error); | ||
682 | 241 | } | ||
683 | 242 | |||
684 | 243 | delete data; | ||
685 | 244 | } | ||
686 | 245 | |||
687 | 246 | void SystemD::copyEnv(const std::string& envname, std::list<std::pair<std::string, std::string>>& env) | ||
688 | 247 | { | ||
689 | 248 | if (!findEnv(envname, env).empty()) | ||
690 | 249 | { | ||
691 | 250 | g_debug("Already a value set for '%s' ignoring", envname.c_str()); | ||
692 | 251 | return; | ||
693 | 252 | } | ||
694 | 253 | |||
695 | 254 | auto cvalue = getenv(envname.c_str()); | ||
696 | 255 | g_debug("Copying Environment: %s", envname.c_str()); | ||
697 | 256 | if (cvalue != nullptr) | ||
698 | 257 | { | ||
699 | 258 | std::string value = getenv(envname.c_str()); | ||
700 | 259 | env.emplace_back(std::make_pair(envname, value)); | ||
701 | 260 | } | ||
702 | 261 | else | ||
703 | 262 | { | ||
704 | 263 | g_debug("Unable to copy environment '%s'", envname.c_str()); | ||
705 | 264 | } | ||
706 | 265 | } | ||
707 | 266 | |||
708 | 267 | void SystemD::copyEnvByPrefix(const std::string& prefix, std::list<std::pair<std::string, std::string>>& env) | ||
709 | 268 | { | ||
710 | 269 | for (unsigned int i = 0; environ[i] != nullptr; i++) | ||
711 | 270 | { | ||
712 | 271 | if (g_str_has_prefix(environ[i], prefix.c_str())) | ||
713 | 272 | { | ||
714 | 273 | std::string envfull = environ[i]; | ||
715 | 274 | std::string envname; | ||
716 | 275 | bool seenequal = false; | ||
717 | 276 | std::remove_copy_if(envfull.begin(), envfull.end(), std::back_inserter(envname), | ||
718 | 277 | [&seenequal](const char c) { | ||
719 | 278 | if (c == '=') | ||
720 | 279 | { | ||
721 | 280 | seenequal = true; | ||
722 | 281 | } | ||
723 | 282 | return seenequal; | ||
724 | 283 | }); | ||
725 | 284 | copyEnv(envname, env); | ||
726 | 285 | } | ||
727 | 286 | } | ||
728 | 287 | } | ||
729 | 288 | |||
730 | 289 | std::shared_ptr<Application::Instance> SystemD::launch( | ||
731 | 290 | const AppID& appId, | ||
732 | 291 | const std::string& job, | ||
733 | 292 | const std::string& instance, | ||
734 | 293 | const std::vector<Application::URL>& urls, | ||
735 | 294 | launchMode mode, | ||
736 | 295 | std::function<std::list<std::pair<std::string, std::string>>(void)>& getenv) | ||
737 | 296 | { | ||
738 | 297 | if (appId.empty()) | ||
739 | 298 | return {}; | ||
740 | 299 | |||
741 | 300 | auto registry = registry_.lock(); | ||
742 | 301 | return registry->impl->thread.executeOnThread<std::shared_ptr<instance::SystemD>>( | ||
743 | 302 | [&]() -> std::shared_ptr<instance::SystemD> { | ||
744 | 303 | auto manager = std::dynamic_pointer_cast<manager::SystemD>(registry->impl->jobs); | ||
745 | 304 | std::string appIdStr{appId}; | ||
746 | 305 | g_debug("Initializing params for an new instance::SystemD for: %s", appIdStr.c_str()); | ||
747 | 306 | |||
748 | 307 | tracepoint(ubuntu_app_launch, libual_start, appIdStr.c_str()); | ||
749 | 308 | |||
750 | 309 | int timeout = 1; | ||
751 | 310 | if (ubuntu::app_launch::Registry::Impl::isWatchingAppStarting()) | ||
752 | 311 | { | ||
753 | 312 | timeout = 0; | ||
754 | 313 | } | ||
755 | 314 | |||
756 | 315 | auto handshake = starting_handshake_start(appIdStr.c_str(), timeout); | ||
757 | 316 | if (handshake == nullptr) | ||
758 | 317 | { | ||
759 | 318 | g_warning("Unable to setup starting handshake"); | ||
760 | 319 | } | ||
761 | 320 | |||
762 | 321 | /* Figure out the unit name for the job */ | ||
763 | 322 | auto unitname = unitName(SystemD::UnitInfo{appIdStr, job, instance}); | ||
764 | 323 | |||
765 | 324 | /* Build up our environment */ | ||
766 | 325 | auto env = getenv(); | ||
767 | 326 | |||
768 | 327 | env.emplace_back(std::make_pair("APP_ID", appIdStr)); /* Application ID */ | ||
769 | 328 | env.emplace_back(std::make_pair("APP_LAUNCHER_PID", std::to_string(getpid()))); /* Who we are, for bugs */ | ||
770 | 329 | |||
771 | 330 | copyEnv("DISPLAY", env); | ||
772 | 331 | copyEnvByPrefix("DBUS_", env); | ||
773 | 332 | copyEnvByPrefix("MIR_", env); | ||
774 | 333 | copyEnvByPrefix("QT_", env); | ||
775 | 334 | copyEnvByPrefix("UBUNTU_", env); | ||
776 | 335 | copyEnvByPrefix("UNITY_", env); | ||
777 | 336 | copyEnvByPrefix("XDG_", env); | ||
778 | 337 | |||
779 | 338 | if (!urls.empty()) | ||
780 | 339 | { | ||
781 | 340 | auto accumfunc = [](const std::string& prev, Application::URL thisurl) -> std::string { | ||
782 | 341 | gchar* gescaped = g_shell_quote(thisurl.value().c_str()); | ||
783 | 342 | std::string escaped; | ||
784 | 343 | if (gescaped != nullptr) | ||
785 | 344 | { | ||
786 | 345 | escaped = gescaped; | ||
787 | 346 | g_free(gescaped); | ||
788 | 347 | } | ||
789 | 348 | else | ||
790 | 349 | { | ||
791 | 350 | g_warning("Unable to escape URL: %s", thisurl.value().c_str()); | ||
792 | 351 | return prev; | ||
793 | 352 | } | ||
794 | 353 | |||
795 | 354 | if (prev.empty()) | ||
796 | 355 | { | ||
797 | 356 | return escaped; | ||
798 | 357 | } | ||
799 | 358 | else | ||
800 | 359 | { | ||
801 | 360 | return prev + " " + escaped; | ||
802 | 361 | } | ||
803 | 362 | }; | ||
804 | 363 | auto urlstring = std::accumulate(urls.begin(), urls.end(), std::string{}, accumfunc); | ||
805 | 364 | env.emplace_back(std::make_pair("APP_URIS", urlstring)); | ||
806 | 365 | } | ||
807 | 366 | |||
808 | 367 | if (mode == launchMode::TEST) | ||
809 | 368 | { | ||
810 | 369 | env.emplace_back(std::make_pair("QT_LOAD_TESTABILITY", "1")); | ||
811 | 370 | } | ||
812 | 371 | |||
813 | 372 | /* Convert to GVariant */ | ||
814 | 373 | GVariantBuilder builder; | ||
815 | 374 | g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE); | ||
816 | 375 | |||
817 | 376 | g_variant_builder_add_value(&builder, g_variant_new_string(unitname.c_str())); | ||
818 | 377 | g_variant_builder_add_value(&builder, g_variant_new_string("replace")); // Job mode | ||
819 | 378 | |||
820 | 379 | /* Parameter Array */ | ||
821 | 380 | g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY); | ||
822 | 381 | |||
823 | 382 | /* Environment */ | ||
824 | 383 | g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE); | ||
825 | 384 | g_variant_builder_add_value(&builder, g_variant_new_string("Environment")); | ||
826 | 385 | g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT); | ||
827 | 386 | g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY); | ||
828 | 387 | for (const auto& envvar : env) | ||
829 | 388 | { | ||
830 | 389 | if (!envvar.first.empty() && !envvar.second.empty()) | ||
831 | 390 | { | ||
832 | 391 | g_variant_builder_add_value(&builder, g_variant_new_take_string(g_strdup_printf( | ||
833 | 392 | "%s=%s", envvar.first.c_str(), envvar.second.c_str()))); | ||
834 | 393 | // g_debug("Setting environment: %s=%s", envvar.first.c_str(), envvar.second.c_str()); | ||
835 | 394 | } | ||
836 | 395 | } | ||
837 | 396 | |||
838 | 397 | g_variant_builder_close(&builder); | ||
839 | 398 | g_variant_builder_close(&builder); | ||
840 | 399 | g_variant_builder_close(&builder); | ||
841 | 400 | |||
842 | 401 | /* ExecStart */ | ||
843 | 402 | auto commands = parseExec(env); | ||
844 | 403 | gchar* pathexec{nullptr}; | ||
845 | 404 | if (!commands.empty() && ((pathexec = g_find_program_in_path(commands[0].c_str())) != nullptr)) | ||
846 | 405 | { | ||
847 | 406 | g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE); | ||
848 | 407 | g_variant_builder_add_value(&builder, g_variant_new_string("ExecStart")); | ||
849 | 408 | g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT); | ||
850 | 409 | g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY); | ||
851 | 410 | |||
852 | 411 | g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE); | ||
853 | 412 | g_variant_builder_add_value(&builder, g_variant_new_take_string(pathexec)); | ||
854 | 413 | |||
855 | 414 | g_variant_builder_open(&builder, G_VARIANT_TYPE_ARRAY); | ||
856 | 415 | for (auto param : commands) | ||
857 | 416 | { | ||
858 | 417 | g_variant_builder_add_value(&builder, g_variant_new_string(param.c_str())); | ||
859 | 418 | } | ||
860 | 419 | g_variant_builder_close(&builder); | ||
861 | 420 | |||
862 | 421 | g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); | ||
863 | 422 | |||
864 | 423 | g_variant_builder_close(&builder); | ||
865 | 424 | g_variant_builder_close(&builder); | ||
866 | 425 | g_variant_builder_close(&builder); | ||
867 | 426 | g_variant_builder_close(&builder); | ||
868 | 427 | } | ||
869 | 428 | |||
870 | 429 | /* RemainAfterExit */ | ||
871 | 430 | g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE); | ||
872 | 431 | g_variant_builder_add_value(&builder, g_variant_new_string("RemainAfterExit")); | ||
873 | 432 | g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT); | ||
874 | 433 | g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); | ||
875 | 434 | g_variant_builder_close(&builder); | ||
876 | 435 | g_variant_builder_close(&builder); | ||
877 | 436 | |||
878 | 437 | /* Type */ | ||
879 | 438 | g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE); | ||
880 | 439 | g_variant_builder_add_value(&builder, g_variant_new_string("Type")); | ||
881 | 440 | g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT); | ||
882 | 441 | g_variant_builder_add_value(&builder, g_variant_new_string("oneshot")); | ||
883 | 442 | g_variant_builder_close(&builder); | ||
884 | 443 | g_variant_builder_close(&builder); | ||
885 | 444 | |||
886 | 445 | /* Working Directory */ | ||
887 | 446 | if (!findEnv("APP_DIR", env).empty()) | ||
888 | 447 | { | ||
889 | 448 | g_variant_builder_open(&builder, G_VARIANT_TYPE_TUPLE); | ||
890 | 449 | g_variant_builder_add_value(&builder, g_variant_new_string("WorkingDirectory")); | ||
891 | 450 | g_variant_builder_open(&builder, G_VARIANT_TYPE_VARIANT); | ||
892 | 451 | g_variant_builder_add_value(&builder, g_variant_new_string(findEnv("APP_DIR", env).c_str())); | ||
893 | 452 | g_variant_builder_close(&builder); | ||
894 | 453 | g_variant_builder_close(&builder); | ||
895 | 454 | } | ||
896 | 455 | |||
897 | 456 | /* Parameter Array */ | ||
898 | 457 | g_variant_builder_close(&builder); | ||
899 | 458 | |||
900 | 459 | /* Dependent Units (none) */ | ||
901 | 460 | g_variant_builder_add_value(&builder, g_variant_new_array(G_VARIANT_TYPE("(sa(sv))"), nullptr, 0)); | ||
902 | 461 | |||
903 | 462 | auto retval = std::make_shared<instance::SystemD>(appId, job, instance, urls, registry); | ||
904 | 463 | auto chelper = new StartCHelper{}; | ||
905 | 464 | chelper->ptr = retval; | ||
906 | 465 | chelper->bus = manager->userbus_; | ||
907 | 466 | |||
908 | 467 | tracepoint(ubuntu_app_launch, handshake_wait, appIdStr.c_str()); | ||
909 | 468 | starting_handshake_wait(handshake); | ||
910 | 469 | tracepoint(ubuntu_app_launch, handshake_complete, appIdStr.c_str()); | ||
911 | 470 | |||
912 | 471 | /* Call the job start function */ | ||
913 | 472 | g_debug("Asking systemd to start task for: %s", appIdStr.c_str()); | ||
914 | 473 | g_dbus_connection_call(manager->userbus_.get(), /* bus */ | ||
915 | 474 | SYSTEMD_DBUS_ADDRESS.c_str(), /* service name */ | ||
916 | 475 | SYSTEMD_DBUS_PATH_MANAGER.c_str(), /* Path */ | ||
917 | 476 | SYSTEMD_DBUS_IFACE_MANAGER.c_str(), /* interface */ | ||
918 | 477 | "StartTransientUnit", /* method */ | ||
919 | 478 | g_variant_builder_end(&builder), /* params */ | ||
920 | 479 | G_VARIANT_TYPE("(o)"), /* return */ | ||
921 | 480 | G_DBUS_CALL_FLAGS_NONE, /* flags */ | ||
922 | 481 | -1, /* default timeout */ | ||
923 | 482 | registry->impl->thread.getCancellable().get(), /* cancellable */ | ||
924 | 483 | application_start_cb, /* callback */ | ||
925 | 484 | chelper /* object */ | ||
926 | 485 | ); | ||
927 | 486 | |||
928 | 487 | tracepoint(ubuntu_app_launch, libual_start_message_sent, appIdStr.c_str()); | ||
929 | 488 | |||
930 | 489 | return retval; | ||
931 | 490 | }); | ||
932 | 491 | } | ||
933 | 492 | |||
934 | 493 | std::shared_ptr<Application::Instance> SystemD::existing(const AppID& appId, | ||
935 | 494 | const std::string& job, | ||
936 | 495 | const std::string& instance, | ||
937 | 496 | const std::vector<Application::URL>& urls) | ||
938 | 497 | { | ||
939 | 498 | return std::make_shared<instance::SystemD>(appId, job, instance, urls, registry_.lock()); | ||
940 | 499 | } | ||
941 | 500 | |||
942 | 501 | std::vector<std::shared_ptr<instance::Base>> SystemD::instances(const AppID& appID, const std::string& job) | ||
943 | 502 | { | ||
944 | 503 | std::vector<std::shared_ptr<instance::Base>> instances; | ||
945 | 504 | auto registry = registry_.lock(); | ||
946 | 505 | std::vector<Application::URL> urls; | ||
947 | 506 | |||
948 | 507 | for (const auto& unit : listUnits()) | ||
949 | 508 | { | ||
950 | 509 | SystemD::UnitInfo unitinfo; | ||
951 | 510 | |||
952 | 511 | try | ||
953 | 512 | { | ||
954 | 513 | unitinfo = parseUnit(unit.id); | ||
955 | 514 | } | ||
956 | 515 | catch (std::runtime_error& e) | ||
957 | 516 | { | ||
958 | 517 | continue; | ||
959 | 518 | } | ||
960 | 519 | |||
961 | 520 | if (job != unitinfo.job) | ||
962 | 521 | { | ||
963 | 522 | continue; | ||
964 | 523 | } | ||
965 | 524 | |||
966 | 525 | if (std::string(appID) != unitinfo.appid) | ||
967 | 526 | { | ||
968 | 527 | continue; | ||
969 | 528 | } | ||
970 | 529 | |||
971 | 530 | instances.emplace_back(std::make_shared<instance::SystemD>(appID, job, unitinfo.inst, urls, registry)); | ||
972 | 531 | } | ||
973 | 532 | |||
974 | 533 | g_debug("Found %d instances for AppID '%s'", int(instances.size()), std::string(appID).c_str()); | ||
975 | 534 | |||
976 | 535 | return instances; | ||
977 | 536 | } | ||
978 | 537 | |||
979 | 538 | std::list<std::shared_ptr<Application>> SystemD::runningApps() | ||
980 | 539 | { | ||
981 | 540 | auto allJobs = getAllJobs(); | ||
982 | 541 | auto registry = registry_.lock(); | ||
983 | 542 | std::set<std::string> appids; | ||
984 | 543 | |||
985 | 544 | for (const auto& unit : listUnits()) | ||
986 | 545 | { | ||
987 | 546 | SystemD::UnitInfo unitinfo; | ||
988 | 547 | |||
989 | 548 | try | ||
990 | 549 | { | ||
991 | 550 | unitinfo = parseUnit(unit.id); | ||
992 | 551 | } | ||
993 | 552 | catch (std::runtime_error& e) | ||
994 | 553 | { | ||
995 | 554 | continue; | ||
996 | 555 | } | ||
997 | 556 | |||
998 | 557 | if (allJobs.find(unitinfo.job) == allJobs.end()) | ||
999 | 558 | { | ||
1000 | 559 | continue; | ||
1001 | 560 | } | ||
1002 | 561 | |||
1003 | 562 | appids.insert(unitinfo.appid); | ||
1004 | 563 | } | ||
1005 | 564 | |||
1006 | 565 | std::list<std::shared_ptr<Application>> apps; | ||
1007 | 566 | for (const auto& appid : appids) | ||
1008 | 567 | { | ||
1009 | 568 | auto id = AppID::find(appid); | ||
1010 | 569 | if (id.empty()) | ||
1011 | 570 | { | ||
1012 | 571 | g_debug("Unable to handle AppID: %s", appid.c_str()); | ||
1013 | 572 | continue; | ||
1014 | 573 | } | ||
1015 | 574 | |||
1016 | 575 | apps.emplace_back(Application::create(id, registry)); | ||
1017 | 576 | } | ||
1018 | 577 | |||
1019 | 578 | return apps; | ||
1020 | 579 | } | ||
1021 | 580 | |||
1022 | 581 | std::string SystemD::userBusPath() | ||
1023 | 582 | { | ||
1024 | 583 | auto cpath = getenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH"); | ||
1025 | 584 | if (cpath != nullptr) | ||
1026 | 585 | { | ||
1027 | 586 | return cpath; | ||
1028 | 587 | } | ||
1029 | 588 | return std::string{"/run/user/"} + std::to_string(getuid()) + std::string{"/bus"}; | ||
1030 | 589 | } | ||
1031 | 590 | |||
1032 | 591 | std::list<SystemD::UnitEntry> SystemD::listUnits() | ||
1033 | 592 | { | ||
1034 | 593 | auto registry = registry_.lock(); | ||
1035 | 594 | return registry->impl->thread.executeOnThread<std::list<SystemD::UnitEntry>>([this, registry]() { | ||
1036 | 595 | GError* error{nullptr}; | ||
1037 | 596 | std::list<SystemD::UnitEntry> ret; | ||
1038 | 597 | |||
1039 | 598 | GVariant* callt = g_dbus_connection_call_sync(userbus_.get(), /* user bus */ | ||
1040 | 599 | SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */ | ||
1041 | 600 | SYSTEMD_DBUS_PATH_MANAGER.c_str(), /* path */ | ||
1042 | 601 | SYSTEMD_DBUS_IFACE_MANAGER.c_str(), /* interface */ | ||
1043 | 602 | "ListUnits", /* method */ | ||
1044 | 603 | nullptr, /* params */ | ||
1045 | 604 | G_VARIANT_TYPE("(a(ssssssouso))"), /* ret type */ | ||
1046 | 605 | G_DBUS_CALL_FLAGS_NONE, /* flags */ | ||
1047 | 606 | -1, /* timeout */ | ||
1048 | 607 | registry->impl->thread.getCancellable().get(), /* cancellable */ | ||
1049 | 608 | &error); | ||
1050 | 609 | |||
1051 | 610 | if (error != nullptr) | ||
1052 | 611 | { | ||
1053 | 612 | auto message = std::string{"Unable to list SystemD units: "} + error->message; | ||
1054 | 613 | g_error_free(error); | ||
1055 | 614 | throw std::runtime_error(message); | ||
1056 | 615 | } | ||
1057 | 616 | |||
1058 | 617 | GVariant* call = g_variant_get_child_value(callt, 0); | ||
1059 | 618 | g_variant_unref(callt); | ||
1060 | 619 | |||
1061 | 620 | const gchar* id; | ||
1062 | 621 | const gchar* description; | ||
1063 | 622 | const gchar* loadState; | ||
1064 | 623 | const gchar* activeState; | ||
1065 | 624 | const gchar* subState; | ||
1066 | 625 | const gchar* following; | ||
1067 | 626 | const gchar* path; | ||
1068 | 627 | guint32 jobId; | ||
1069 | 628 | const gchar* jobType; | ||
1070 | 629 | const gchar* jobPath; | ||
1071 | 630 | auto iter = g_variant_iter_new(call); | ||
1072 | 631 | while (g_variant_iter_loop(iter, "(&s&s&s&s&s&s&ou&s&o)", &id, &description, &loadState, &activeState, | ||
1073 | 632 | &subState, &following, &path, &jobId, &jobType, &jobPath)) | ||
1074 | 633 | { | ||
1075 | 634 | ret.emplace_back(SystemD::UnitEntry{id, description, loadState, activeState, subState, following, path, | ||
1076 | 635 | jobId, jobType, jobPath}); | ||
1077 | 636 | } | ||
1078 | 637 | |||
1079 | 638 | g_variant_iter_free(iter); | ||
1080 | 639 | g_variant_unref(call); | ||
1081 | 640 | |||
1082 | 641 | return ret; | ||
1083 | 642 | }); | ||
1084 | 643 | } | ||
1085 | 644 | |||
1086 | 645 | /* TODO: Application job names */ | ||
1087 | 646 | const std::regex unitNaming{ | ||
1088 | 647 | "^ubuntu\\-app\\-launch\\-(application\\-(?:click|legacy|snap))\\-(.*)\\-([0-9]*)\\.service$"}; | ||
1089 | 648 | |||
1090 | 649 | SystemD::UnitInfo SystemD::parseUnit(const std::string& unit) | ||
1091 | 650 | { | ||
1092 | 651 | std::smatch match; | ||
1093 | 652 | if (!std::regex_match(unit, match, unitNaming)) | ||
1094 | 653 | { | ||
1095 | 654 | throw std::runtime_error{"Unable to parse unit name: " + unit}; | ||
1096 | 655 | } | ||
1097 | 656 | |||
1098 | 657 | return {match[2].str(), match[1].str(), match[3].str()}; | ||
1099 | 658 | } | ||
1100 | 659 | |||
1101 | 660 | std::string SystemD::unitName(const SystemD::UnitInfo& info) | ||
1102 | 661 | { | ||
1103 | 662 | return std::string{"ubuntu-app-launch-"} + info.job + "-" + info.appid + "-" + info.inst + ".service"; | ||
1104 | 663 | } | ||
1105 | 664 | |||
1106 | 665 | /** Function that uses and maintains the cache of the paths for units | ||
1107 | 666 | on the systemd dbus connection. If we already have the entry in the | ||
1108 | 667 | cache we just return the path and this function is fast. If not we have | ||
1109 | 668 | to ask systemd for it and that can take a bit longer. | ||
1110 | 669 | |||
1111 | 670 | After getting the data we throw a small background task in to clean | ||
1112 | 671 | up the cache if it has more than 50 entries. We delete those who | ||
1113 | 672 | haven't be used for an hour. | ||
1114 | 673 | */ | ||
1115 | 674 | std::string SystemD::unitPath(const std::string& unitName) | ||
1116 | 675 | { | ||
1117 | 676 | auto registry = registry_.lock(); | ||
1118 | 677 | std::string retval; | ||
1119 | 678 | |||
1120 | 679 | if (true) | ||
1121 | 680 | { | ||
1122 | 681 | /* Create a context for the gaurd */ | ||
1123 | 682 | std::lock_guard<std::mutex> guard(unitPathsMutex_); | ||
1124 | 683 | auto iter = std::find_if(unitPaths_.begin(), unitPaths_.end(), | ||
1125 | 684 | [&unitName](const SystemD::UnitPath& entry) { return entry.unitName == unitName; }); | ||
1126 | 685 | |||
1127 | 686 | if (iter != unitPaths_.end()) | ||
1128 | 687 | { | ||
1129 | 688 | retval = iter->unitPath; | ||
1130 | 689 | iter->timeStamp = std::chrono::system_clock::now(); | ||
1131 | 690 | } | ||
1132 | 691 | } | ||
1133 | 692 | |||
1134 | 693 | if (retval.empty()) | ||
1135 | 694 | { | ||
1136 | 695 | retval = registry->impl->thread.executeOnThread<std::string>([this, registry, unitName]() { | ||
1137 | 696 | std::string path; | ||
1138 | 697 | GError* error{nullptr}; | ||
1139 | 698 | GVariant* call = | ||
1140 | 699 | g_dbus_connection_call_sync(userbus_.get(), /* user bus */ | ||
1141 | 700 | SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */ | ||
1142 | 701 | SYSTEMD_DBUS_PATH_MANAGER.c_str(), /* path */ | ||
1143 | 702 | SYSTEMD_DBUS_IFACE_MANAGER.c_str(), /* interface */ | ||
1144 | 703 | "GetUnit", /* method */ | ||
1145 | 704 | g_variant_new("(s)", unitName.c_str()), /* params */ | ||
1146 | 705 | G_VARIANT_TYPE("(o)"), /* ret type */ | ||
1147 | 706 | G_DBUS_CALL_FLAGS_NONE, /* flags */ | ||
1148 | 707 | -1, /* timeout */ | ||
1149 | 708 | registry->impl->thread.getCancellable().get(), /* cancellable */ | ||
1150 | 709 | &error); | ||
1151 | 710 | |||
1152 | 711 | if (error != nullptr) | ||
1153 | 712 | { | ||
1154 | 713 | auto message = std::string{"Unable to get SystemD unit path for '"} + unitName + std::string{"': "} + | ||
1155 | 714 | error->message; | ||
1156 | 715 | g_error_free(error); | ||
1157 | 716 | throw std::runtime_error(message); | ||
1158 | 717 | } | ||
1159 | 718 | |||
1160 | 719 | /* Parse variant */ | ||
1161 | 720 | gchar* gpath = nullptr; | ||
1162 | 721 | g_variant_get(call, "(o)", &gpath); | ||
1163 | 722 | if (gpath != nullptr) | ||
1164 | 723 | { | ||
1165 | 724 | std::lock_guard<std::mutex> guard(unitPathsMutex_); | ||
1166 | 725 | path = gpath; | ||
1167 | 726 | unitPaths_.emplace_back(SystemD::UnitPath{unitName, path, std::chrono::system_clock::now()}); | ||
1168 | 727 | } | ||
1169 | 728 | |||
1170 | 729 | g_variant_unref(call); | ||
1171 | 730 | |||
1172 | 731 | return path; | ||
1173 | 732 | }); | ||
1174 | 733 | } | ||
1175 | 734 | |||
1176 | 735 | /* Queue a possible cleanup */ | ||
1177 | 736 | if (unitPaths_.size() > 50) | ||
1178 | 737 | { | ||
1179 | 738 | /* TODO: We should look at UnitRemoved as well */ | ||
1180 | 739 | /* TODO: Add to cache on UnitNew */ | ||
1181 | 740 | registry->impl->thread.executeOnThread([this] { | ||
1182 | 741 | std::lock_guard<std::mutex> guard(unitPathsMutex_); | ||
1183 | 742 | std::remove_if(unitPaths_.begin(), unitPaths_.end(), [](const SystemD::UnitPath& entry) -> bool { | ||
1184 | 743 | auto age = std::chrono::system_clock::now() - entry.timeStamp; | ||
1185 | 744 | return age > std::chrono::hours{1}; | ||
1186 | 745 | }); | ||
1187 | 746 | }); | ||
1188 | 747 | } | ||
1189 | 748 | |||
1190 | 749 | return retval; | ||
1191 | 750 | } | ||
1192 | 751 | |||
1193 | 752 | pid_t SystemD::unitPrimaryPid(const AppID& appId, const std::string& job, const std::string& instance) | ||
1194 | 753 | { | ||
1195 | 754 | auto registry = registry_.lock(); | ||
1196 | 755 | auto unitname = unitName(SystemD::UnitInfo{appId, job, instance}); | ||
1197 | 756 | auto unitpath = unitPath(unitname); | ||
1198 | 757 | |||
1199 | 758 | return registry->impl->thread.executeOnThread<pid_t>([this, registry, unitname, unitpath]() { | ||
1200 | 759 | GError* error{nullptr}; | ||
1201 | 760 | GVariant* call = g_dbus_connection_call_sync( | ||
1202 | 761 | userbus_.get(), /* user bus */ | ||
1203 | 762 | SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */ | ||
1204 | 763 | unitpath.c_str(), /* path */ | ||
1205 | 764 | "org.freedesktop.DBus.Properties", /* interface */ | ||
1206 | 765 | "Get", /* method */ | ||
1207 | 766 | g_variant_new("(ss)", SYSTEMD_DBUS_IFACE_SERVICE.c_str(), "MainPID"), /* params */ | ||
1208 | 767 | G_VARIANT_TYPE("(v)"), /* ret type */ | ||
1209 | 768 | G_DBUS_CALL_FLAGS_NONE, /* flags */ | ||
1210 | 769 | -1, /* timeout */ | ||
1211 | 770 | registry->impl->thread.getCancellable().get(), /* cancellable */ | ||
1212 | 771 | &error); | ||
1213 | 772 | |||
1214 | 773 | if (error != nullptr) | ||
1215 | 774 | { | ||
1216 | 775 | auto message = | ||
1217 | 776 | std::string{"Unable to get SystemD PID for '"} + unitname + std::string{"': "} + error->message; | ||
1218 | 777 | g_error_free(error); | ||
1219 | 778 | throw std::runtime_error(message); | ||
1220 | 779 | } | ||
1221 | 780 | |||
1222 | 781 | /* Parse variant */ | ||
1223 | 782 | GVariant* vpid{nullptr}; | ||
1224 | 783 | g_variant_get(call, "(v)", &vpid); | ||
1225 | 784 | g_variant_unref(call); | ||
1226 | 785 | |||
1227 | 786 | pid_t pid; | ||
1228 | 787 | pid = g_variant_get_uint32(vpid); | ||
1229 | 788 | g_variant_unref(vpid); | ||
1230 | 789 | |||
1231 | 790 | return pid; | ||
1232 | 791 | }); | ||
1233 | 792 | } | ||
1234 | 793 | |||
1235 | 794 | std::vector<pid_t> SystemD::unitPids(const AppID& appId, const std::string& job, const std::string& instance) | ||
1236 | 795 | { | ||
1237 | 796 | auto registry = registry_.lock(); | ||
1238 | 797 | auto unitname = unitName(SystemD::UnitInfo{appId, job, instance}); | ||
1239 | 798 | auto unitpath = unitPath(unitname); | ||
1240 | 799 | |||
1241 | 800 | auto cgrouppath = registry->impl->thread.executeOnThread<std::string>([this, registry, unitname, unitpath]() { | ||
1242 | 801 | GError* error{nullptr}; | ||
1243 | 802 | GVariant* call = g_dbus_connection_call_sync( | ||
1244 | 803 | userbus_.get(), /* user bus */ | ||
1245 | 804 | SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */ | ||
1246 | 805 | unitpath.c_str(), /* path */ | ||
1247 | 806 | "org.freedesktop.DBus.Properties", /* interface */ | ||
1248 | 807 | "Get", /* method */ | ||
1249 | 808 | g_variant_new("(ss)", SYSTEMD_DBUS_IFACE_SERVICE.c_str(), "ControlGroup"), /* params */ | ||
1250 | 809 | G_VARIANT_TYPE("(v)"), /* ret type */ | ||
1251 | 810 | G_DBUS_CALL_FLAGS_NONE, /* flags */ | ||
1252 | 811 | -1, /* timeout */ | ||
1253 | 812 | registry->impl->thread.getCancellable().get(), /* cancellable */ | ||
1254 | 813 | &error); | ||
1255 | 814 | |||
1256 | 815 | if (error != nullptr) | ||
1257 | 816 | { | ||
1258 | 817 | auto message = std::string{"Unable to get SystemD Control Group for '"} + unitname + std::string{"': "} + | ||
1259 | 818 | error->message; | ||
1260 | 819 | g_error_free(error); | ||
1261 | 820 | throw std::runtime_error(message); | ||
1262 | 821 | } | ||
1263 | 822 | |||
1264 | 823 | /* Parse variant */ | ||
1265 | 824 | GVariant* vstring = nullptr; | ||
1266 | 825 | g_variant_get(call, "(v)", &vstring); | ||
1267 | 826 | g_variant_unref(call); | ||
1268 | 827 | |||
1269 | 828 | if (vstring == nullptr) | ||
1270 | 829 | { | ||
1271 | 830 | return std::string{}; | ||
1272 | 831 | } | ||
1273 | 832 | |||
1274 | 833 | std::string group; | ||
1275 | 834 | auto ggroup = g_variant_get_string(vstring, nullptr); | ||
1276 | 835 | if (ggroup != nullptr) | ||
1277 | 836 | { | ||
1278 | 837 | group = ggroup; | ||
1279 | 838 | } | ||
1280 | 839 | g_variant_unref(vstring); | ||
1281 | 840 | |||
1282 | 841 | return group; | ||
1283 | 842 | }); | ||
1284 | 843 | |||
1285 | 844 | gchar* fullpath = g_build_filename("/sys", "fs", "cgroup", "systemd", cgrouppath.c_str(), "tasks", nullptr); | ||
1286 | 845 | gchar* pidstr = nullptr; | ||
1287 | 846 | GError* error = nullptr; | ||
1288 | 847 | |||
1289 | 848 | g_debug("Getting PIDs from %s", fullpath); | ||
1290 | 849 | g_file_get_contents(fullpath, &pidstr, nullptr, &error); | ||
1291 | 850 | g_free(fullpath); | ||
1292 | 851 | |||
1293 | 852 | if (error != nullptr) | ||
1294 | 853 | { | ||
1295 | 854 | g_warning("Unable to read cgroup PID list: %s", error->message); | ||
1296 | 855 | g_error_free(error); | ||
1297 | 856 | return {}; | ||
1298 | 857 | } | ||
1299 | 858 | |||
1300 | 859 | gchar** pidlines = g_strsplit(pidstr, "\n", -1); | ||
1301 | 860 | g_free(pidstr); | ||
1302 | 861 | std::vector<pid_t> pids; | ||
1303 | 862 | |||
1304 | 863 | for (auto i = 0; pidlines[i] != nullptr; i++) | ||
1305 | 864 | { | ||
1306 | 865 | const gchar* pidline = pidlines[i]; | ||
1307 | 866 | if (pidline[0] != '\n') | ||
1308 | 867 | { | ||
1309 | 868 | auto pid = std::atoi(pidline); | ||
1310 | 869 | if (pid != 0) | ||
1311 | 870 | { | ||
1312 | 871 | pids.emplace_back(pid); | ||
1313 | 872 | } | ||
1314 | 873 | } | ||
1315 | 874 | } | ||
1316 | 875 | |||
1317 | 876 | g_strfreev(pidlines); | ||
1318 | 877 | |||
1319 | 878 | return pids; | ||
1320 | 879 | } | ||
1321 | 880 | |||
1322 | 881 | void SystemD::stopUnit(const AppID& appId, const std::string& job, const std::string& instance) | ||
1323 | 882 | { | ||
1324 | 883 | auto registry = registry_.lock(); | ||
1325 | 884 | auto unitname = unitName(SystemD::UnitInfo{appId, job, instance}); | ||
1326 | 885 | |||
1327 | 886 | registry->impl->thread.executeOnThread<bool>([this, registry, unitname] { | ||
1328 | 887 | GError* error{nullptr}; | ||
1329 | 888 | GVariant* call = g_dbus_connection_call_sync(userbus_.get(), /* user bus */ | ||
1330 | 889 | SYSTEMD_DBUS_ADDRESS.c_str(), /* bus name */ | ||
1331 | 890 | SYSTEMD_DBUS_PATH_MANAGER.c_str(), /* path */ | ||
1332 | 891 | SYSTEMD_DBUS_IFACE_MANAGER.c_str(), /* interface */ | ||
1333 | 892 | "StopUnit", /* method */ | ||
1334 | 893 | g_variant_new("(ss)", unitname.c_str(), "fail"), /* params */ | ||
1335 | 894 | G_VARIANT_TYPE("(o)"), /* ret type */ | ||
1336 | 895 | G_DBUS_CALL_FLAGS_NONE, /* flags */ | ||
1337 | 896 | -1, /* timeout */ | ||
1338 | 897 | registry->impl->thread.getCancellable().get(), /* cancellable */ | ||
1339 | 898 | &error); | ||
1340 | 899 | |||
1341 | 900 | if (error != nullptr) | ||
1342 | 901 | { | ||
1343 | 902 | auto message = | ||
1344 | 903 | std::string{"Unable to get SystemD to stop '"} + unitname + std::string{"': "} + error->message; | ||
1345 | 904 | g_error_free(error); | ||
1346 | 905 | throw std::runtime_error(message); | ||
1347 | 906 | } | ||
1348 | 907 | |||
1349 | 908 | g_variant_unref(call); | ||
1350 | 909 | |||
1351 | 910 | return true; | ||
1352 | 911 | }); | ||
1353 | 912 | } | ||
1354 | 913 | |||
1355 | 914 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& SystemD::appStarted() | ||
1356 | 915 | { | ||
1357 | 916 | g_warning("Systemd signals not implemented"); | ||
1358 | 917 | return sig_appStarted; | ||
1359 | 918 | } | ||
1360 | 919 | |||
1361 | 920 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& SystemD::appStopped() | ||
1362 | 921 | { | ||
1363 | 922 | g_warning("Systemd signals not implemented"); | ||
1364 | 923 | return sig_appStopped; | ||
1365 | 924 | } | ||
1366 | 925 | |||
1367 | 926 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>& | ||
1368 | 927 | SystemD::appFailed() | ||
1369 | 928 | { | ||
1370 | 929 | g_warning("Systemd signals not implemented"); | ||
1371 | 930 | return sig_appFailed; | ||
1372 | 931 | } | ||
1373 | 932 | |||
1374 | 933 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& | ||
1375 | 934 | SystemD::appPaused() | ||
1376 | 935 | { | ||
1377 | 936 | g_warning("Systemd signals not implemented"); | ||
1378 | 937 | return sig_appPaused; | ||
1379 | 938 | } | ||
1380 | 939 | |||
1381 | 940 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& | ||
1382 | 941 | SystemD::appResumed() | ||
1383 | 942 | { | ||
1384 | 943 | g_warning("Systemd signals not implemented"); | ||
1385 | 944 | return sig_appResumed; | ||
1386 | 945 | } | ||
1387 | 946 | |||
1388 | 947 | } // namespace manager | ||
1389 | 948 | } // namespace jobs | ||
1390 | 949 | } // namespace app_launch | ||
1391 | 950 | } // namespace ubuntu | ||
1392 | 0 | 951 | ||
1393 | === added file 'libubuntu-app-launch/jobs-systemd.h' | |||
1394 | --- libubuntu-app-launch/jobs-systemd.h 1970-01-01 00:00:00 +0000 | |||
1395 | +++ libubuntu-app-launch/jobs-systemd.h 2016-11-10 21:59:02 +0000 | |||
1396 | @@ -0,0 +1,123 @@ | |||
1397 | 1 | /* | ||
1398 | 2 | * Copyright © 2016 Canonical Ltd. | ||
1399 | 3 | * | ||
1400 | 4 | * This program is free software: you can redistribute it and/or modify it | ||
1401 | 5 | * under the terms of the GNU General Public License version 3, as published | ||
1402 | 6 | * by the Free Software Foundation. | ||
1403 | 7 | * | ||
1404 | 8 | * This program is distributed in the hope that it will be useful, but | ||
1405 | 9 | * WITHOUT ANY WARRANTY; without even the implied warranties of | ||
1406 | 10 | * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR | ||
1407 | 11 | * PURPOSE. See the GNU General Public License for more details. | ||
1408 | 12 | * | ||
1409 | 13 | * You should have received a copy of the GNU General Public License along | ||
1410 | 14 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1411 | 15 | * | ||
1412 | 16 | * Authors: | ||
1413 | 17 | * Ted Gould <ted.gould@canonical.com> | ||
1414 | 18 | */ | ||
1415 | 19 | |||
1416 | 20 | #pragma once | ||
1417 | 21 | |||
1418 | 22 | #include "jobs-base.h" | ||
1419 | 23 | #include <chrono> | ||
1420 | 24 | #include <gio/gio.h> | ||
1421 | 25 | #include <map> | ||
1422 | 26 | #include <mutex> | ||
1423 | 27 | |||
1424 | 28 | namespace ubuntu | ||
1425 | 29 | { | ||
1426 | 30 | namespace app_launch | ||
1427 | 31 | { | ||
1428 | 32 | namespace jobs | ||
1429 | 33 | { | ||
1430 | 34 | namespace manager | ||
1431 | 35 | { | ||
1432 | 36 | |||
1433 | 37 | class SystemD : public Base | ||
1434 | 38 | { | ||
1435 | 39 | public: | ||
1436 | 40 | SystemD(std::shared_ptr<Registry> registry); | ||
1437 | 41 | virtual ~SystemD(); | ||
1438 | 42 | |||
1439 | 43 | virtual std::shared_ptr<Application::Instance> launch( | ||
1440 | 44 | const AppID& appId, | ||
1441 | 45 | const std::string& job, | ||
1442 | 46 | const std::string& instance, | ||
1443 | 47 | const std::vector<Application::URL>& urls, | ||
1444 | 48 | launchMode mode, | ||
1445 | 49 | std::function<std::list<std::pair<std::string, std::string>>(void)>& getenv) override; | ||
1446 | 50 | virtual std::shared_ptr<Application::Instance> existing(const AppID& appId, | ||
1447 | 51 | const std::string& job, | ||
1448 | 52 | const std::string& instance, | ||
1449 | 53 | const std::vector<Application::URL>& urls) override; | ||
1450 | 54 | |||
1451 | 55 | virtual std::list<std::shared_ptr<Application>> runningApps() override; | ||
1452 | 56 | |||
1453 | 57 | virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) override; | ||
1454 | 58 | |||
1455 | 59 | virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStarted() override; | ||
1456 | 60 | virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStopped() override; | ||
1457 | 61 | virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>& | ||
1458 | 62 | appFailed() override; | ||
1459 | 63 | virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& | ||
1460 | 64 | appPaused() override; | ||
1461 | 65 | virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& | ||
1462 | 66 | appResumed() override; | ||
1463 | 67 | |||
1464 | 68 | static std::string userBusPath(); | ||
1465 | 69 | |||
1466 | 70 | pid_t unitPrimaryPid(const AppID& appId, const std::string& job, const std::string& instance); | ||
1467 | 71 | std::vector<pid_t> unitPids(const AppID& appId, const std::string& job, const std::string& instance); | ||
1468 | 72 | void stopUnit(const AppID& appId, const std::string& job, const std::string& instance); | ||
1469 | 73 | |||
1470 | 74 | private: | ||
1471 | 75 | std::shared_ptr<GDBusConnection> userbus_; | ||
1472 | 76 | |||
1473 | 77 | /* ssssssouso */ | ||
1474 | 78 | struct UnitEntry | ||
1475 | 79 | { | ||
1476 | 80 | std::string id; | ||
1477 | 81 | std::string description; | ||
1478 | 82 | std::string loadState; | ||
1479 | 83 | std::string activeState; | ||
1480 | 84 | std::string subState; | ||
1481 | 85 | std::string following; | ||
1482 | 86 | std::string path; | ||
1483 | 87 | std::uint32_t jobId; | ||
1484 | 88 | std::string jobType; | ||
1485 | 89 | std::string jobPath; | ||
1486 | 90 | }; | ||
1487 | 91 | std::list<UnitEntry> listUnits(); | ||
1488 | 92 | |||
1489 | 93 | struct UnitInfo | ||
1490 | 94 | { | ||
1491 | 95 | std::string appid; | ||
1492 | 96 | std::string job; | ||
1493 | 97 | std::string inst; | ||
1494 | 98 | }; | ||
1495 | 99 | UnitInfo parseUnit(const std::string& unit); | ||
1496 | 100 | std::string unitName(const UnitInfo& info); | ||
1497 | 101 | |||
1498 | 102 | struct UnitPath | ||
1499 | 103 | { | ||
1500 | 104 | std::string unitName; | ||
1501 | 105 | std::string unitPath; | ||
1502 | 106 | std::chrono::time_point<std::chrono::system_clock> timeStamp; | ||
1503 | 107 | }; | ||
1504 | 108 | std::list<UnitPath> unitPaths_; | ||
1505 | 109 | std::mutex unitPathsMutex_; | ||
1506 | 110 | std::string unitPath(const std::string& unitName); | ||
1507 | 111 | |||
1508 | 112 | static std::string findEnv(const std::string& value, std::list<std::pair<std::string, std::string>>& env); | ||
1509 | 113 | static void copyEnv(const std::string& envname, std::list<std::pair<std::string, std::string>>& env); | ||
1510 | 114 | static void copyEnvByPrefix(const std::string& prefix, std::list<std::pair<std::string, std::string>>& env); | ||
1511 | 115 | |||
1512 | 116 | static std::vector<std::string> parseExec(std::list<std::pair<std::string, std::string>>& env); | ||
1513 | 117 | static void application_start_cb(GObject* obj, GAsyncResult* res, gpointer user_data); | ||
1514 | 118 | }; | ||
1515 | 119 | |||
1516 | 120 | } // namespace manager | ||
1517 | 121 | } // namespace jobs | ||
1518 | 122 | } // namespace app_launch | ||
1519 | 123 | } // namespace ubuntu | ||
1520 | 0 | 124 | ||
1521 | === modified file 'libubuntu-app-launch/jobs-upstart.cpp' | |||
1522 | --- libubuntu-app-launch/jobs-upstart.cpp 2016-11-10 21:59:01 +0000 | |||
1523 | +++ libubuntu-app-launch/jobs-upstart.cpp 2016-11-10 21:59:02 +0000 | |||
1524 | @@ -73,8 +73,6 @@ | |||
1525 | 73 | private: | 73 | private: |
1526 | 74 | std::string upstartJobPath(const std::string& job); | 74 | std::string upstartJobPath(const std::string& job); |
1527 | 75 | std::string upstartName(); | 75 | std::string upstartName(); |
1528 | 76 | |||
1529 | 77 | static std::shared_ptr<gchar*> urlsToStrv(const std::vector<Application::URL>& urls); | ||
1530 | 78 | }; | 76 | }; |
1531 | 79 | 77 | ||
1532 | 80 | /** Uses Upstart to get the primary PID of the instance using Upstart's | 78 | /** Uses Upstart to get the primary PID of the instance using Upstart's |
1533 | @@ -306,29 +304,6 @@ | |||
1534 | 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()); |
1535 | 307 | } | 305 | } |
1536 | 308 | 306 | ||
1537 | 309 | /** Reformat a C++ vector of URLs into a C GStrv of strings | ||
1538 | 310 | |||
1539 | 311 | \param urls Vector of URLs to make into C strings | ||
1540 | 312 | */ | ||
1541 | 313 | std::shared_ptr<gchar*> Upstart::urlsToStrv(const std::vector<Application::URL>& urls) | ||
1542 | 314 | { | ||
1543 | 315 | if (urls.empty()) | ||
1544 | 316 | { | ||
1545 | 317 | return {}; | ||
1546 | 318 | } | ||
1547 | 319 | |||
1548 | 320 | auto array = g_array_new(TRUE, FALSE, sizeof(gchar*)); | ||
1549 | 321 | |||
1550 | 322 | for (auto url : urls) | ||
1551 | 323 | { | ||
1552 | 324 | auto str = g_strdup(url.value().c_str()); | ||
1553 | 325 | g_debug("Converting URL: %s", str); | ||
1554 | 326 | g_array_append_val(array, str); | ||
1555 | 327 | } | ||
1556 | 328 | |||
1557 | 329 | return std::shared_ptr<gchar*>((gchar**)g_array_free(array, FALSE), g_strfreev); | ||
1558 | 330 | } | ||
1559 | 331 | |||
1560 | 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 */ |
1561 | 333 | struct StartCHelper | 308 | struct StartCHelper |
1562 | 334 | { | 309 | { |
1563 | 335 | 310 | ||
1564 | === modified file 'libubuntu-app-launch/registry-impl.cpp' | |||
1565 | --- libubuntu-app-launch/registry-impl.cpp 2016-11-10 21:59:01 +0000 | |||
1566 | +++ libubuntu-app-launch/registry-impl.cpp 2016-11-10 21:59:02 +0000 | |||
1567 | @@ -144,7 +144,7 @@ | |||
1568 | 144 | if (error != nullptr) | 144 | if (error != nullptr) |
1569 | 145 | { | 145 | { |
1570 | 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); }); |
1572 | 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); |
1573 | 148 | return std::shared_ptr<JsonObject>(); | 148 | return std::shared_ptr<JsonObject>(); |
1574 | 149 | } | 149 | } |
1575 | 150 | 150 | ||
1576 | 151 | 151 | ||
1577 | === modified file 'libubuntu-app-launch/snapd-info.cpp' | |||
1578 | --- libubuntu-app-launch/snapd-info.cpp 2016-10-03 23:54:08 +0000 | |||
1579 | +++ libubuntu-app-launch/snapd-info.cpp 2016-11-10 21:59:02 +0000 | |||
1580 | @@ -170,7 +170,7 @@ | |||
1581 | 170 | } | 170 | } |
1582 | 171 | catch (std::runtime_error &e) | 171 | catch (std::runtime_error &e) |
1583 | 172 | { | 172 | { |
1585 | 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()); |
1586 | 174 | return {}; | 174 | return {}; |
1587 | 175 | } | 175 | } |
1588 | 176 | } | 176 | } |
1589 | 177 | 177 | ||
1590 | === modified file 'tests/exec-util-test.cc' | |||
1591 | --- tests/exec-util-test.cc 2016-09-15 17:13:04 +0000 | |||
1592 | +++ tests/exec-util-test.cc 2016-11-10 21:59:02 +0000 | |||
1593 | @@ -45,6 +45,7 @@ | |||
1594 | 45 | g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE); | 45 | g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE); |
1595 | 46 | g_setenv("UBUNTU_APP_LAUNCH_LIBERTINE_LAUNCH", "libertine-launch", TRUE); | 46 | g_setenv("UBUNTU_APP_LAUNCH_LIBERTINE_LAUNCH", "libertine-launch", TRUE); |
1596 | 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); |
1597 | 48 | g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE); | ||
1598 | 48 | 49 | ||
1599 | 49 | service = dbus_test_service_new(NULL); | 50 | service = dbus_test_service_new(NULL); |
1600 | 50 | 51 | ||
1601 | @@ -184,12 +185,15 @@ | |||
1602 | 184 | EXPECT_STREQ("grep", value); }}, | 185 | EXPECT_STREQ("grep", value); }}, |
1603 | 185 | {"APP_ID", [](const gchar * value) { | 186 | {"APP_ID", [](const gchar * value) { |
1604 | 186 | EXPECT_STREQ("com.test.good_application_1.2.3", value); }}, | 187 | EXPECT_STREQ("com.test.good_application_1.2.3", value); }}, |
1605 | 188 | {"APP_EXEC_POLICY", [](const gchar * value) { | ||
1606 | 189 | EXPECT_STREQ("com.test.good_application_1.2.3", value); }}, | ||
1607 | 187 | {"APP_LAUNCHER_PID", [](const gchar * value) { | 190 | {"APP_LAUNCHER_PID", [](const gchar * value) { |
1608 | 188 | EXPECT_EQ(getpid(), atoi(value)); }}, | 191 | EXPECT_EQ(getpid(), atoi(value)); }}, |
1609 | 189 | {"APP_DESKTOP_FILE_PATH", [](const gchar * value) { | 192 | {"APP_DESKTOP_FILE_PATH", [](const gchar * value) { |
1610 | 190 | EXPECT_STREQ(APP_DIR "/application.desktop", value); }}, | 193 | EXPECT_STREQ(APP_DIR "/application.desktop", value); }}, |
1611 | 191 | {"APP_XMIR_ENABLE", [](const gchar * value) { | 194 | {"APP_XMIR_ENABLE", [](const gchar * value) { |
1612 | 192 | EXPECT_STREQ("0", value); }}, | 195 | EXPECT_STREQ("0", value); }}, |
1613 | 196 | {"QML2_IMPORT_PATH", nocheck}, | ||
1614 | 193 | }); | 197 | }); |
1615 | 194 | 198 | ||
1616 | 195 | #undef APP_DIR | 199 | #undef APP_DIR |
1617 | @@ -267,10 +271,13 @@ | |||
1618 | 267 | {"APP_EXEC", nocheck}, | 271 | {"APP_EXEC", nocheck}, |
1619 | 268 | {"APP_ID", [](const gchar * value) { | 272 | {"APP_ID", [](const gchar * value) { |
1620 | 269 | EXPECT_STREQ("com.test.mir_mir_1", value); }}, | 273 | EXPECT_STREQ("com.test.mir_mir_1", value); }}, |
1621 | 274 | {"APP_EXEC_POLICY", [](const gchar * value) { | ||
1622 | 275 | EXPECT_STREQ("com.test.mir_mir_1", value); }}, | ||
1623 | 270 | {"APP_LAUNCHER_PID", nocheck}, | 276 | {"APP_LAUNCHER_PID", nocheck}, |
1624 | 271 | {"APP_DESKTOP_FILE_PATH", nocheck}, | 277 | {"APP_DESKTOP_FILE_PATH", nocheck}, |
1625 | 272 | {"APP_XMIR_ENABLE", [](const gchar * value) { | 278 | {"APP_XMIR_ENABLE", [](const gchar * value) { |
1626 | 273 | EXPECT_STREQ("1", value); }}, | 279 | EXPECT_STREQ("1", value); }}, |
1627 | 280 | {"QML2_IMPORT_PATH", nocheck}, | ||
1628 | 274 | }); | 281 | }); |
1629 | 275 | } | 282 | } |
1630 | 276 | 283 | ||
1631 | @@ -289,10 +296,13 @@ | |||
1632 | 289 | {"APP_EXEC", nocheck}, | 296 | {"APP_EXEC", nocheck}, |
1633 | 290 | {"APP_ID", [](const gchar * value) { | 297 | {"APP_ID", [](const gchar * value) { |
1634 | 291 | EXPECT_STREQ("com.test.mir_nomir_1", value); }}, | 298 | EXPECT_STREQ("com.test.mir_nomir_1", value); }}, |
1635 | 299 | {"APP_EXEC_POLICY", [](const gchar * value) { | ||
1636 | 300 | EXPECT_STREQ("com.test.mir_nomir_1", value); }}, | ||
1637 | 292 | {"APP_LAUNCHER_PID", nocheck}, | 301 | {"APP_LAUNCHER_PID", nocheck}, |
1638 | 293 | {"APP_DESKTOP_FILE_PATH", nocheck}, | 302 | {"APP_DESKTOP_FILE_PATH", nocheck}, |
1639 | 294 | {"APP_XMIR_ENABLE", [](const gchar * value) { | 303 | {"APP_XMIR_ENABLE", [](const gchar * value) { |
1640 | 295 | EXPECT_STREQ("0", value); }}, | 304 | EXPECT_STREQ("0", value); }}, |
1641 | 305 | {"QML2_IMPORT_PATH", nocheck}, | ||
1642 | 296 | }); | 306 | }); |
1643 | 297 | } | 307 | } |
1644 | 298 | 308 | ||
1645 | 299 | 309 | ||
1646 | === modified file 'tests/libual-cpp-test.cc' | |||
1647 | --- tests/libual-cpp-test.cc 2016-11-10 21:59:01 +0000 | |||
1648 | +++ tests/libual-cpp-test.cc 2016-11-10 21:59:02 +0000 | |||
1649 | @@ -149,6 +149,7 @@ | |||
1650 | 149 | g_setenv("UBUNTU_APP_LAUNCH_DISABLE_SNAPD_TIMEOUT", "You betcha!", TRUE); | 149 | g_setenv("UBUNTU_APP_LAUNCH_DISABLE_SNAPD_TIMEOUT", "You betcha!", TRUE); |
1651 | 150 | g_unlink(SNAPD_TEST_SOCKET); | 150 | g_unlink(SNAPD_TEST_SOCKET); |
1652 | 151 | #endif | 151 | #endif |
1653 | 152 | g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE); | ||
1654 | 152 | 153 | ||
1655 | 153 | service = dbus_test_service_new(NULL); | 154 | service = dbus_test_service_new(NULL); |
1656 | 154 | 155 | ||
1657 | 155 | 156 | ||
1658 | === modified file 'tests/libual-test.cc' | |||
1659 | --- tests/libual-test.cc 2016-09-14 15:29:35 +0000 | |||
1660 | +++ tests/libual-test.cc 2016-11-10 21:59:02 +0000 | |||
1661 | @@ -90,6 +90,7 @@ | |||
1662 | 90 | g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE); | 90 | g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE); |
1663 | 91 | 91 | ||
1664 | 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); |
1665 | 93 | g_setenv("UBUNTU_APP_LAUNCH_SYSTEMD_PATH", "/this/should/not/exist", TRUE); | ||
1666 | 93 | 94 | ||
1667 | 94 | service = dbus_test_service_new(NULL); | 95 | service = dbus_test_service_new(NULL); |
1668 | 95 | 96 | ||
1669 | 96 | 97 | ||
1670 | === modified file 'xmir-helper.c' | |||
1671 | --- xmir-helper.c 2015-08-11 02:41:08 +0000 | |||
1672 | +++ xmir-helper.c 2016-11-10 21:59:02 +0000 | |||
1673 | @@ -86,6 +86,8 @@ | |||
1674 | 86 | NULL | 86 | NULL |
1675 | 87 | }; | 87 | }; |
1676 | 88 | 88 | ||
1677 | 89 | printf("Executing XMir on PID: %d", getpid()); | ||
1678 | 90 | |||
1679 | 89 | return execv(xmir, xmirexec); | 91 | return execv(xmir, xmirexec); |
1680 | 90 | } | 92 | } |
1681 | 91 | 93 |