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