Merge lp:~mterry/qtmir/warn-on-xapp into lp:qtmir
- warn-on-xapp
- Merge into trunk
Status: | Work in progress |
---|---|
Proposed branch: | lp:~mterry/qtmir/warn-on-xapp |
Merge into: | lp:qtmir |
Prerequisite: | lp:~mterry/qtmir/more-accurate-mocks |
Diff against target: |
837 lines (+256/-146) 13 files modified
CMakeLists.txt (+1/-1) debian/changelog (+6/-0) debian/control (+2/-2) debian/gles-patches/convert-to-gles.patch (+1/-1) src/modules/Unity/Application/application_manager.cpp (+51/-36) src/modules/Unity/Application/application_manager.h (+1/-0) src/modules/Unity/Application/taskcontroller.h (+1/-0) src/modules/Unity/Application/upstart/taskcontroller.cpp (+86/-77) src/modules/Unity/Application/upstart/taskcontroller.h (+1/-0) tests/framework/mock_task_controller.cpp (+13/-0) tests/framework/mock_task_controller.h (+3/-0) tests/framework/qtmir_test.cpp (+1/-0) tests/modules/ApplicationManager/application_manager_test.cpp (+89/-29) |
To merge this branch: | bzr merge lp:~mterry/qtmir/warn-on-xapp |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity8 CI Bot (community) | continuous-integration | Needs Fixing | |
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Mir development team | Pending | ||
Review via email: mp+279172@code.launchpad.net |
Commit message
Support new ubuntu-app-launch API changes that let upper layers approve whether an application starts.
Specifically, we now take the UAL signals and pass them on to Unity to later approve.
Description of the change
Support new ubuntu-app-launch API changes that let upper layers approve whether an application starts.
Specifically, we now take the UAL signals and pass them on to Unity to later approve.
Related branches:
https:/
https:/
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
Gerry Boland (gerboland) wrote : | # |
I'm hesitant to review this until the UAL MP has been approved, as it strongly depends on the UAL changes, which UAL maintainer may not like.
On the other hand, I suspect we're the UAL maintainers now
Gerry Boland (gerboland) wrote : | # |
Am told UAL is under discussion, so this MP is blocked until that's complete
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:427
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
- 428. By Michael Terry
-
Merge from trunk; disabled actual hooks for signals, will fix later
- 429. By Michael Terry
-
Go back to checking start return value
- 430. By Michael Terry
-
Start porting to app object signals, still won't work
- 431. By Michael Terry
-
remove some unused code from a bad merge
Unmerged revisions
- 431. By Michael Terry
-
remove some unused code from a bad merge
- 430. By Michael Terry
-
Start porting to app object signals, still won't work
- 429. By Michael Terry
-
Go back to checking start return value
- 428. By Michael Terry
-
Merge from trunk; disabled actual hooks for signals, will fix later
- 427. By Michael Terry
-
Remove/delete app if it is denied, so that its internal state doesn't hang around
- 426. By Michael Terry
-
Update to handle latest unity-api branch
- 425. By Michael Terry
-
Merge from trunk
- 424. By Michael Terry
-
Initial cut of supporting app starting approval api in ubuntu-app-launch
- 423. By Michael Terry
-
Merge more-accurate-mocks
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2016-04-26 07:20:33 +0000 |
3 | +++ CMakeLists.txt 2016-05-17 13:14:09 +0000 |
4 | @@ -76,7 +76,7 @@ |
5 | pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt) |
6 | pkg_check_modules(QTDBUSTEST libqtdbustest-1 REQUIRED) |
7 | pkg_check_modules(QTDBUSMOCK libqtdbusmock-1 REQUIRED) |
8 | -pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=15) |
9 | +pkg_check_modules(APPLICATION_API REQUIRED unity-shell-application=16) |
10 | |
11 | include_directories(${APPLICATION_API_INCLUDE_DIRS}) |
12 | |
13 | |
14 | === modified file 'debian/changelog' |
15 | --- debian/changelog 2016-05-11 09:08:29 +0000 |
16 | +++ debian/changelog 2016-05-17 13:14:09 +0000 |
17 | @@ -1,3 +1,9 @@ |
18 | +qtmir (0.4.9) UNRELEASED; urgency=medium |
19 | + |
20 | + * Add support for approving applications before they finish starting |
21 | + |
22 | + -- Michael Terry <mterry@ubuntu.com> Tue, 01 Dec 2015 09:55:49 -0500 |
23 | + |
24 | qtmir (0.4.8+16.04.20160511-0ubuntu1) xenial; urgency=medium |
25 | |
26 | [ Daniel d'Andrada ] |
27 | |
28 | === modified file 'debian/control' |
29 | --- debian/control 2016-04-28 12:48:42 +0000 |
30 | +++ debian/control 2016-05-17 13:14:09 +0000 |
31 | @@ -22,7 +22,7 @@ |
32 | libubuntu-app-launch2-dev (>= 0.9), |
33 | libubuntu-application-api-dev (>= 2.1.0), |
34 | libudev-dev, |
35 | - libunity-api-dev (>= 7.110), |
36 | + libunity-api-dev (>= 7.112), |
37 | liburl-dispatcher1-dev, |
38 | libxkbcommon-dev, |
39 | libxrender-dev, |
40 | @@ -93,7 +93,7 @@ |
41 | Conflicts: libqtmir, |
42 | libunity-mir1, |
43 | Provides: unity-application-impl, |
44 | - unity-application-impl-15, |
45 | + unity-application-impl-16, |
46 | Description: Qt plugin for Unity specific Mir APIs |
47 | QtMir provides Qt/QML bindings for Mir features that are exposed through the |
48 | qtmir-desktop or qtmir-android QPA plugin such as Application management |
49 | |
50 | === modified file 'debian/gles-patches/convert-to-gles.patch' |
51 | --- debian/gles-patches/convert-to-gles.patch 2016-04-06 18:12:31 +0000 |
52 | +++ debian/gles-patches/convert-to-gles.patch 2016-05-17 13:14:09 +0000 |
53 | @@ -84,7 +84,7 @@ |
54 | -Conflicts: libqtmir, |
55 | - libunity-mir1, |
56 | -Provides: unity-application-impl, |
57 | -- unity-application-impl-15, |
58 | +- unity-application-impl-16, |
59 | -Description: Qt plugin for Unity specific Mir APIs |
60 | - QtMir provides Qt/QML bindings for Mir features that are exposed through the |
61 | - qtmir-desktop or qtmir-android QPA plugin such as Application management |
62 | |
63 | === modified file 'src/modules/Unity/Application/application_manager.cpp' |
64 | --- src/modules/Unity/Application/application_manager.cpp 2016-04-29 20:04:51 +0000 |
65 | +++ src/modules/Unity/Application/application_manager.cpp 2016-05-17 13:14:09 +0000 |
66 | @@ -348,29 +348,24 @@ |
67 | } |
68 | |
69 | if (!m_taskController->start(appId, arguments)) { |
70 | - qWarning() << "Upstart failed to start application with appId" << appId; |
71 | - return nullptr; |
72 | - } |
73 | - |
74 | - // The TaskController may synchroneously callback onProcessStarting, so check if application already added |
75 | - application = findApplication(appId); |
76 | - if (application) { |
77 | - application->setArguments(arguments); |
78 | - } else { |
79 | - auto appInfo = m_taskController->getInfoForApp(appId); |
80 | - if (!appInfo) { |
81 | - qCWarning(QTMIR_APPLICATIONS) << "ApplicationManager::startApplication - Unable to instantiate application with appId" << appId; |
82 | - return nullptr; |
83 | - } |
84 | - |
85 | - application = new Application( |
86 | - m_sharedWakelock, |
87 | - appInfo, |
88 | - arguments, |
89 | - this); |
90 | - |
91 | - add(application); |
92 | - } |
93 | + qCWarning(QTMIR_APPLICATIONS) << "ApplicationManager::startApplication - Unable to start application with appId" << appId; |
94 | + return nullptr; |
95 | + } |
96 | + |
97 | + auto appInfo = m_taskController->getInfoForApp(appId); |
98 | + if (!appInfo) { |
99 | + qCWarning(QTMIR_APPLICATIONS) << "ApplicationManager::startApplication - Unable to instantiate application with appId" << appId; |
100 | + return nullptr; |
101 | + } |
102 | + |
103 | + application = new Application( |
104 | + m_sharedWakelock, |
105 | + appInfo, |
106 | + arguments, |
107 | + this); |
108 | + |
109 | + add(application); |
110 | + |
111 | return application; |
112 | } |
113 | |
114 | @@ -393,20 +388,40 @@ |
115 | QStringList(), |
116 | this); |
117 | add(application); |
118 | + } |
119 | + |
120 | + Q_EMIT applicationStartApprovalRequested(appId); |
121 | +} |
122 | + |
123 | +bool ApplicationManager::approveApplicationStart(const QString &appId, bool approved) |
124 | +{ |
125 | + qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::approveApplicationStart - appId=" << appId << "approved=" << approved; |
126 | + |
127 | + Application *application = findApplication(appId); |
128 | + if (!application) |
129 | + return false; |
130 | + |
131 | + // Allow stopped apps because url-dispatcher can relaunch apps which have |
132 | + // been OOM-killed - AppMan must accept the newly spawned application and |
133 | + // focus it immediately (as user expects app to still be running). |
134 | + if (application->state() != Application::Starting && |
135 | + application->internalState() != Application::InternalState::StoppedResumable) { |
136 | + return false; |
137 | + } |
138 | + |
139 | + if (!m_taskController->approveStart(application->appId(), approved)) |
140 | + return false; |
141 | + |
142 | + if (approved) { |
143 | + application->setProcessState(Application::ProcessRunning); |
144 | application->requestFocus(); |
145 | - } |
146 | - else { |
147 | - if (application->internalState() == Application::InternalState::StoppedResumable) { |
148 | - // url-dispatcher can relaunch apps which have been OOM-killed - AppMan must accept the newly spawned |
149 | - // application and focus it immediately (as user expects app to still be running). |
150 | - qCDebug(QTMIR_APPLICATIONS) << "Stopped application appId=" << appId << "is being resumed externally"; |
151 | - application->requestFocus(); |
152 | - } else { |
153 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStarting application already found with appId" |
154 | - << appId; |
155 | - } |
156 | - } |
157 | - application->setProcessState(Application::ProcessRunning); |
158 | + } else { |
159 | + application->close(); |
160 | + remove(application); |
161 | + delete application; |
162 | + } |
163 | + |
164 | + return true; |
165 | } |
166 | |
167 | /** |
168 | |
169 | === modified file 'src/modules/Unity/Application/application_manager.h' |
170 | --- src/modules/Unity/Application/application_manager.h 2016-04-26 08:56:36 +0000 |
171 | +++ src/modules/Unity/Application/application_manager.h 2016-05-17 13:14:09 +0000 |
172 | @@ -89,6 +89,7 @@ |
173 | Q_INVOKABLE bool requestFocusApplication(const QString &appId) override; |
174 | Q_INVOKABLE qtmir::Application* startApplication(const QString &appId, const QStringList &arguments = QStringList()) override; |
175 | Q_INVOKABLE bool stopApplication(const QString &appId) override; |
176 | + Q_INVOKABLE bool approveApplicationStart(const QString &appId, bool approved) override; |
177 | |
178 | // QAbstractListModel |
179 | int rowCount(const QModelIndex & parent = QModelIndex()) const override; |
180 | |
181 | === modified file 'src/modules/Unity/Application/taskcontroller.h' |
182 | --- src/modules/Unity/Application/taskcontroller.h 2016-04-22 14:03:26 +0000 |
183 | +++ src/modules/Unity/Application/taskcontroller.h 2016-05-17 13:14:09 +0000 |
184 | @@ -48,6 +48,7 @@ |
185 | |
186 | virtual bool stop(const QString &appId) = 0; |
187 | virtual bool start(const QString &appId, const QStringList &arguments) = 0; |
188 | + virtual bool approveStart(const QString &appId, bool approved) = 0; |
189 | |
190 | virtual bool suspend(const QString &appId) = 0; |
191 | virtual bool resume(const QString &appId) = 0; |
192 | |
193 | === modified file 'src/modules/Unity/Application/upstart/taskcontroller.cpp' |
194 | --- src/modules/Unity/Application/upstart/taskcontroller.cpp 2016-04-22 14:03:26 +0000 |
195 | +++ src/modules/Unity/Application/upstart/taskcontroller.cpp 2016-05-17 13:14:09 +0000 |
196 | @@ -24,10 +24,7 @@ |
197 | // Qt |
198 | #include <QStandardPaths> |
199 | |
200 | -// upstart |
201 | -extern "C" { |
202 | - #include "ubuntu-app-launch.h" |
203 | -} |
204 | +// UAL |
205 | #include <ubuntu-app-launch/registry.h> |
206 | |
207 | namespace ual = ubuntu::app_launch; |
208 | @@ -37,34 +34,18 @@ |
209 | namespace upstart |
210 | { |
211 | |
212 | -struct TaskController::Private |
213 | -{ |
214 | - std::shared_ptr<ual::Registry> registry; |
215 | - UbuntuAppLaunchAppObserver preStartCallback = nullptr; |
216 | - UbuntuAppLaunchAppObserver startedCallback = nullptr; |
217 | - UbuntuAppLaunchAppObserver stopCallback = nullptr; |
218 | - UbuntuAppLaunchAppObserver focusCallback = nullptr; |
219 | - UbuntuAppLaunchAppObserver resumeCallback = nullptr; |
220 | - UbuntuAppLaunchAppPausedResumedObserver pausedCallback = nullptr; |
221 | - UbuntuAppLaunchAppFailedObserver failureCallback = nullptr; |
222 | -}; |
223 | - |
224 | namespace { |
225 | /** |
226 | * @brief toShortAppIdIfPossible |
227 | * @param appId - any string that you think is an appId |
228 | * @return if a valid appId was input, a shortened appId is returned, else returns the input string unaltered |
229 | */ |
230 | -QString toShortAppIdIfPossible(const QString &appId) { |
231 | - gchar *package, *application; |
232 | - if (ubuntu_app_launch_app_id_parse(appId.toLatin1().constData(), &package, &application, nullptr)) { |
233 | - // is long appId, so assemble its short appId |
234 | - QString shortAppId = QString("%1_%2").arg(package).arg(application); |
235 | - g_free(package); |
236 | - g_free(application); |
237 | - return shortAppId; |
238 | +QString toShortAppIdIfPossible(const std::shared_ptr<ual::Application> &app) { |
239 | + const ual::AppID &appId = app->appId(); |
240 | + if (ual::AppID::valid(std::string(appId))) { |
241 | + return QString::fromStdString(appId.package) + "_" + QString::fromStdString(appId.appname); |
242 | } else { |
243 | - return appId; |
244 | + return QString::fromStdString(std::string(appId)); |
245 | } |
246 | } |
247 | |
248 | @@ -80,72 +61,89 @@ |
249 | |
250 | } // namespace |
251 | |
252 | +class TaskController::Private : public ual::Registry::Manager |
253 | +{ |
254 | +public: |
255 | + Private() : ual::Registry::Manager() {}; |
256 | + |
257 | + TaskController *parent = nullptr; |
258 | + std::shared_ptr<ual::Registry> registry; |
259 | + std::shared_ptr<core::ScopedConnection> startedCallback; |
260 | + std::shared_ptr<core::ScopedConnection> stopCallback; |
261 | + std::shared_ptr<core::ScopedConnection> resumeCallback; |
262 | + std::shared_ptr<core::ScopedConnection> pausedCallback; |
263 | + std::shared_ptr<core::ScopedConnection> failureCallback; |
264 | + |
265 | + bool focusRequest(std::shared_ptr<ual::Application> app, |
266 | + std::shared_ptr<ual::Application::Instance>) override |
267 | + { |
268 | + Q_EMIT parent->focusRequested(toShortAppIdIfPossible(app)); |
269 | + return true; |
270 | + } |
271 | + |
272 | + bool startingRequest(std::shared_ptr<ual::Application> app, |
273 | + std::shared_ptr<ual::Application::Instance>) override |
274 | + { |
275 | + Q_EMIT parent->processStarting(toShortAppIdIfPossible(app)); |
276 | + return true; |
277 | + } |
278 | +}; |
279 | + |
280 | TaskController::TaskController() |
281 | : qtmir::TaskController(), |
282 | impl(new Private()) |
283 | { |
284 | + impl->parent = this; |
285 | impl->registry = std::make_shared<ual::Registry>(); |
286 | |
287 | - impl->preStartCallback = [](const gchar * appId, gpointer userData) { |
288 | - auto thiz = static_cast<TaskController*>(userData); |
289 | - Q_EMIT(thiz->processStarting(toShortAppIdIfPossible(appId))); |
290 | - }; |
291 | - |
292 | - impl->startedCallback = [](const gchar * appId, gpointer userData) { |
293 | - auto thiz = static_cast<TaskController*>(userData); |
294 | - Q_EMIT(thiz->applicationStarted(toShortAppIdIfPossible(appId))); |
295 | - }; |
296 | - |
297 | - impl->stopCallback = [](const gchar * appId, gpointer userData) { |
298 | - auto thiz = static_cast<TaskController*>(userData); |
299 | - Q_EMIT(thiz->processStopped(toShortAppIdIfPossible(appId))); |
300 | - }; |
301 | - |
302 | - impl->focusCallback = [](const gchar * appId, gpointer userData) { |
303 | - auto thiz = static_cast<TaskController*>(userData); |
304 | - Q_EMIT(thiz->focusRequested(toShortAppIdIfPossible(appId))); |
305 | - }; |
306 | - |
307 | - impl->resumeCallback = [](const gchar * appId, gpointer userData) { |
308 | - auto thiz = static_cast<TaskController*>(userData); |
309 | - Q_EMIT(thiz->resumeRequested(toShortAppIdIfPossible(appId))); |
310 | - }; |
311 | - |
312 | - impl->pausedCallback = [](const gchar * appId, GPid *, gpointer userData) { |
313 | - auto thiz = static_cast<TaskController*>(userData); |
314 | - Q_EMIT(thiz->processSuspended(toShortAppIdIfPossible(appId))); |
315 | - }; |
316 | - |
317 | - impl->failureCallback = [](const gchar * appId, UbuntuAppLaunchAppFailed failureType, gpointer userData) { |
318 | + impl->registry->setManager(impl.data()); |
319 | + |
320 | + impl->startedCallback = std::make_shared<core::ScopedConnection>( |
321 | + impl->registry->appStarted().connect( |
322 | + [this](std::shared_ptr<ual::Application> app, |
323 | + std::shared_ptr<ual::Application::Instance>) { |
324 | + Q_EMIT applicationStarted(toShortAppIdIfPossible(app)); |
325 | + })); |
326 | + |
327 | + impl->stopCallback = std::make_shared<core::ScopedConnection>( |
328 | + impl->registry->appStopped().connect( |
329 | + [this](std::shared_ptr<ual::Application> app, |
330 | + std::shared_ptr<ual::Application::Instance>) { |
331 | + Q_EMIT processStopped(toShortAppIdIfPossible(app)); |
332 | + })); |
333 | + |
334 | + impl->resumeCallback = std::make_shared<core::ScopedConnection>( |
335 | + impl->registry->appResumed().connect( |
336 | + [this](std::shared_ptr<ual::Application> app, |
337 | + std::shared_ptr<ual::Application::Instance>) { |
338 | + Q_EMIT resumeRequested(toShortAppIdIfPossible(app)); |
339 | + })); |
340 | + |
341 | + impl->pausedCallback = std::make_shared<core::ScopedConnection>( |
342 | + impl->registry->appPaused().connect( |
343 | + [this](std::shared_ptr<ual::Application> app, |
344 | + std::shared_ptr<ual::Application::Instance>) { |
345 | + Q_EMIT processSuspended(toShortAppIdIfPossible(app)); |
346 | + })); |
347 | + |
348 | + impl->failureCallback = std::make_shared<core::ScopedConnection>( |
349 | + impl->registry->appFailed().connect( |
350 | + [this](std::shared_ptr<ual::Application> app, |
351 | + std::shared_ptr<ual::Application::Instance>, |
352 | + ual::Registry::FailureType failureType) { |
353 | TaskController::Error error; |
354 | switch(failureType) |
355 | { |
356 | - case UBUNTU_APP_LAUNCH_APP_FAILED_CRASH: error = TaskController::Error::APPLICATION_CRASHED; |
357 | - case UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE: error = TaskController::Error::APPLICATION_FAILED_TO_START; |
358 | + case ual::Registry::FailureType::CRASH: error = TaskController::Error::APPLICATION_CRASHED; |
359 | + case ual::Registry::FailureType::START_FAILURE: error = TaskController::Error::APPLICATION_FAILED_TO_START; |
360 | } |
361 | |
362 | - auto thiz = static_cast<TaskController*>(userData); |
363 | - Q_EMIT(thiz->processFailed(toShortAppIdIfPossible(appId), error)); |
364 | - }; |
365 | - |
366 | - ubuntu_app_launch_observer_add_app_starting(impl->preStartCallback, this); |
367 | - ubuntu_app_launch_observer_add_app_started(impl->startedCallback, this); |
368 | - ubuntu_app_launch_observer_add_app_stop(impl->stopCallback, this); |
369 | - ubuntu_app_launch_observer_add_app_focus(impl->focusCallback, this); |
370 | - ubuntu_app_launch_observer_add_app_resume(impl->resumeCallback, this); |
371 | - ubuntu_app_launch_observer_add_app_paused(impl->pausedCallback, this); |
372 | - ubuntu_app_launch_observer_add_app_failed(impl->failureCallback, this); |
373 | + Q_EMIT processFailed(toShortAppIdIfPossible(app), error); |
374 | + })); |
375 | } |
376 | |
377 | TaskController::~TaskController() |
378 | { |
379 | - ubuntu_app_launch_observer_delete_app_starting(impl->preStartCallback, this); |
380 | - ubuntu_app_launch_observer_delete_app_started(impl->startedCallback, this); |
381 | - ubuntu_app_launch_observer_delete_app_stop(impl->stopCallback, this); |
382 | - ubuntu_app_launch_observer_delete_app_focus(impl->focusCallback, this); |
383 | - ubuntu_app_launch_observer_delete_app_resume(impl->resumeCallback, this); |
384 | - ubuntu_app_launch_observer_delete_app_paused(impl->pausedCallback, this); |
385 | - ubuntu_app_launch_observer_delete_app_failed(impl->failureCallback, this); |
386 | } |
387 | |
388 | bool TaskController::appIdHasProcessId(const QString& appId, pid_t pid) |
389 | @@ -196,6 +194,17 @@ |
390 | return true; |
391 | } |
392 | |
393 | +bool TaskController::approveStart(const QString& appId, bool approved) |
394 | +{ |
395 | + auto app = createApp(appId, impl->registry); |
396 | + if (!app) { |
397 | + return false; |
398 | + } |
399 | + |
400 | + Q_UNUSED(approved); // TODO |
401 | + return true; |
402 | +} |
403 | + |
404 | bool TaskController::suspend(const QString& appId) |
405 | { |
406 | auto app = createApp(appId, impl->registry); |
407 | @@ -231,7 +240,7 @@ |
408 | return QSharedPointer<qtmir::ApplicationInfo>(); |
409 | } |
410 | |
411 | - QString shortAppId = toShortAppIdIfPossible(QString::fromStdString(std::string(app->appId()))); |
412 | + QString shortAppId = toShortAppIdIfPossible(app); |
413 | auto appInfo = new qtmir::upstart::ApplicationInfo(shortAppId, app->info()); |
414 | return QSharedPointer<qtmir::ApplicationInfo>(appInfo); |
415 | } |
416 | |
417 | === modified file 'src/modules/Unity/Application/upstart/taskcontroller.h' |
418 | --- src/modules/Unity/Application/upstart/taskcontroller.h 2016-04-22 14:03:26 +0000 |
419 | +++ src/modules/Unity/Application/upstart/taskcontroller.h 2016-05-17 13:14:09 +0000 |
420 | @@ -35,6 +35,7 @@ |
421 | |
422 | bool stop(const QString& appId) override; |
423 | bool start(const QString& appId, const QStringList& arguments) override; |
424 | + bool approveStart(const QString& appId, bool approved) override; |
425 | |
426 | bool suspend(const QString& appId) override; |
427 | bool resume(const QString& appId) override; |
428 | |
429 | === modified file 'tests/framework/mock_task_controller.cpp' |
430 | --- tests/framework/mock_task_controller.cpp 2016-04-22 14:03:26 +0000 |
431 | +++ tests/framework/mock_task_controller.cpp 2016-05-17 13:14:09 +0000 |
432 | @@ -40,6 +40,10 @@ |
433 | .WillByDefault( |
434 | Invoke(this, &MockTaskController::doStart)); |
435 | |
436 | + ON_CALL(*this, approveStart(_, _)) |
437 | + .WillByDefault( |
438 | + Invoke(this, &MockTaskController::doApproveStart)); |
439 | + |
440 | ON_CALL(*this, suspend(_)) |
441 | .WillByDefault( |
442 | Invoke(this, &MockTaskController::doSuspend)); |
443 | @@ -100,6 +104,15 @@ |
444 | } |
445 | |
446 | |
447 | +bool MockTaskController::doApproveStart(const QString &appId, bool approved) |
448 | +{ |
449 | + Q_UNUSED(appId); |
450 | + Q_UNUSED(approved); |
451 | + |
452 | + return true; |
453 | +} |
454 | + |
455 | + |
456 | bool MockTaskController::doSuspend(const QString &appId) |
457 | { |
458 | Q_UNUSED(appId); |
459 | |
460 | === modified file 'tests/framework/mock_task_controller.h' |
461 | --- tests/framework/mock_task_controller.h 2016-04-22 14:03:26 +0000 |
462 | +++ tests/framework/mock_task_controller.h 2016-05-17 13:14:09 +0000 |
463 | @@ -36,6 +36,7 @@ |
464 | |
465 | MOCK_METHOD1(stop, bool(const QString&)); |
466 | MOCK_METHOD2(start, bool(const QString&, const QStringList&)); |
467 | + MOCK_METHOD2(approveStart, bool(const QString&, bool)); |
468 | MOCK_METHOD1(suspend, bool(const QString&)); |
469 | MOCK_METHOD1(resume, bool(const QString&)); |
470 | |
471 | @@ -47,6 +48,8 @@ |
472 | |
473 | bool doStart(const QString& appId, const QStringList& args); |
474 | |
475 | + bool doApproveStart(const QString& appId, bool approved); |
476 | + |
477 | bool doSuspend(const QString& appId); |
478 | |
479 | bool doResume(const QString& appId); |
480 | |
481 | === modified file 'tests/framework/qtmir_test.cpp' |
482 | --- tests/framework/qtmir_test.cpp 2016-04-29 20:04:51 +0000 |
483 | +++ tests/framework/qtmir_test.cpp 2016-05-17 13:14:09 +0000 |
484 | @@ -148,6 +148,7 @@ |
485 | |
486 | auto application = applicationManager.startApplication(appId); |
487 | applicationManager.onProcessStarting(appId); |
488 | + applicationManager.approveApplicationStart(appId, true); |
489 | |
490 | bool authed = false; |
491 | applicationManager.authorizeSession(procId, authed); |
492 | |
493 | === modified file 'tests/modules/ApplicationManager/application_manager_test.cpp' |
494 | --- tests/modules/ApplicationManager/application_manager_test.cpp 2016-04-26 08:56:36 +0000 |
495 | +++ tests/modules/ApplicationManager/application_manager_test.cpp 2016-05-17 13:14:09 +0000 |
496 | @@ -46,6 +46,10 @@ |
497 | applicationManager.onSessionStarting(session); |
498 | sessionManager.onSessionStarting(session); |
499 | } |
500 | + inline void onProcessStarting(const QString &appId) { |
501 | + applicationManager.onProcessStarting(appId); |
502 | + ASSERT_TRUE(applicationManager.approveApplicationStart(appId, true)); |
503 | + } |
504 | inline void onSessionStopping(const std::shared_ptr<mir::scene::Session> &session) { |
505 | applicationManager.onSessionStopping(session); |
506 | sessionManager.onSessionStopping(session); |
507 | @@ -115,6 +119,7 @@ |
508 | // now a second session without desktop file is launched: |
509 | applicationManager.authorizeSession(secondProcId, authed); |
510 | applicationManager.onProcessStarting(dialer_app_id); |
511 | + EXPECT_FALSE(applicationManager.approveApplicationStart(dialer_app_id, true)); |
512 | |
513 | EXPECT_FALSE(authed); |
514 | EXPECT_EQ(application, applicationManager.findApplication(dialer_app_id)); |
515 | @@ -137,7 +142,7 @@ |
516 | applicationManager.authorizeSession(procId, authed); |
517 | onSessionStarting(mirSession); |
518 | Application * beforeFailure = applicationManager.findApplication(app_id); |
519 | - applicationManager.onProcessStarting(app_id); |
520 | + onProcessStarting(app_id); |
521 | onSessionStopping(mirSession); |
522 | applicationManager.onProcessFailed(app_id, TaskController::Error::APPLICATION_FAILED_TO_START); |
523 | Application * afterFailure = applicationManager.findApplication(app_id); |
524 | @@ -351,7 +356,7 @@ |
525 | EXPECT_EQ(Application::Starting, app->state()); |
526 | |
527 | // Signal app is ready now |
528 | - applicationManager.onProcessStarting("app"); |
529 | + onProcessStarting("app"); |
530 | onSessionCreatedSurface(session.get(), aSurface); |
531 | aSurface->drawFirstFrame(); |
532 | |
533 | @@ -470,7 +475,7 @@ |
534 | QSignalSpy focusSpy(&applicationManager, SIGNAL(focusRequested(const QString &))); |
535 | |
536 | // upstart sends notification that the application was started |
537 | - applicationManager.onProcessStarting(appId); |
538 | + onProcessStarting(appId); |
539 | |
540 | Application *theApp = applicationManager.findApplication(appId); |
541 | |
542 | @@ -585,7 +590,7 @@ |
543 | ON_CALL(*taskController, start(appId, _)) |
544 | .WillByDefault(Invoke( |
545 | [&](const QString &appId, Unused) { |
546 | - applicationManager.onProcessStarting(appId); |
547 | + onProcessStarting(appId); |
548 | return true; |
549 | } |
550 | )); |
551 | @@ -608,6 +613,61 @@ |
552 | } |
553 | |
554 | /* |
555 | + * Test that we don't start running the app until we get approval |
556 | + */ |
557 | +TEST_F(ApplicationManagerTests, appStartingIsBlockedUntilApproval) |
558 | +{ |
559 | + using namespace ::testing; |
560 | + const QString appId("testAppId"); |
561 | + |
562 | + // Now test that asking the app manager to start an app gets down to the app controller |
563 | + EXPECT_CALL(*taskController, start(appId, _)).Times(1); |
564 | + auto application = applicationManager.startApplication(appId); |
565 | + ASSERT_TRUE(Mock::VerifyAndClearExpectations(taskController)); |
566 | + ASSERT_EQ(Application::Starting, application->state()); |
567 | + ASSERT_EQ(Application::ProcessUnknown, application->processState()); |
568 | + |
569 | + // Now pretend that app controller signals that the process is starting |
570 | + QSignalSpy approvalRequestSpy(&applicationManager, SIGNAL(applicationStartApprovalRequested(const QString &))); |
571 | + applicationManager.onProcessStarting(appId); |
572 | + ASSERT_EQ(1, approvalRequestSpy.count()); |
573 | + ASSERT_EQ(Application::Starting, application->state()); |
574 | + ASSERT_EQ(Application::ProcessUnknown, application->processState()); |
575 | + |
576 | + // Now pretend that unity or whatever handled the approval request |
577 | + QSignalSpy focusRequestSpy(&applicationManager, SIGNAL(focusRequested(const QString &))); |
578 | + EXPECT_CALL(*taskController, approveStart(appId, true)).Times(1); |
579 | + ASSERT_TRUE(applicationManager.approveApplicationStart(appId, true)); |
580 | + ASSERT_TRUE(Mock::VerifyAndClearExpectations(taskController)); |
581 | + ASSERT_EQ(1, focusRequestSpy.count()); |
582 | + ASSERT_EQ(Application::Starting, application->state()); |
583 | + ASSERT_EQ(Application::ProcessRunning, application->processState()); |
584 | +} |
585 | + |
586 | +/* |
587 | + * Test that we don't start running the app until we get approval |
588 | + */ |
589 | +TEST_F(ApplicationManagerTests, appStartingDenialClosesApplication) |
590 | +{ |
591 | + using namespace ::testing; |
592 | + const QString appId("testAppId"); |
593 | + |
594 | + // Set up Mocks & signal watcher |
595 | + EXPECT_CALL(*taskController, approveStart(appId, false)).Times(1); |
596 | + QSignalSpy focusRequestSpy(&applicationManager, SIGNAL(focusRequested(const QString &))); |
597 | + |
598 | + // Start app |
599 | + applicationManager.startApplication(appId); |
600 | + applicationManager.onProcessStarting(appId); |
601 | + |
602 | + // Deny app |
603 | + ASSERT_TRUE(applicationManager.approveApplicationStart(appId, false)); |
604 | + |
605 | + ASSERT_EQ(0, focusRequestSpy.count()); |
606 | + ASSERT_EQ(nullptr, applicationManager.findApplication(appId)); |
607 | +} |
608 | + |
609 | +/* |
610 | * Test that the child sessions of a webapp process are accepted |
611 | */ |
612 | TEST_F(ApplicationManagerTests,webAppSecondarySessionsAccepted) |
613 | @@ -664,7 +724,7 @@ |
614 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
615 | |
616 | // upstart sends notification that the application was started |
617 | - applicationManager.onProcessStarting(appId); |
618 | + onProcessStarting(appId); |
619 | |
620 | // check no new signals were emitted and application state unchanged |
621 | EXPECT_EQ(countSpy.count(), 0); |
622 | @@ -692,7 +752,7 @@ |
623 | .WillOnce(Return(true)); |
624 | |
625 | applicationManager.startApplication(appId); |
626 | - applicationManager.onProcessStarting(appId); |
627 | + onProcessStarting(appId); |
628 | |
629 | QSignalSpy countSpy(&applicationManager, SIGNAL(countChanged())); |
630 | |
631 | @@ -730,7 +790,7 @@ |
632 | .WillOnce(Return(true)); |
633 | |
634 | applicationManager.startApplication(appId); |
635 | - applicationManager.onProcessStarting(appId); |
636 | + onProcessStarting(appId); |
637 | |
638 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
639 | |
640 | @@ -765,7 +825,7 @@ |
641 | .WillOnce(Return(true)); |
642 | |
643 | applicationManager.startApplication(appId); |
644 | - applicationManager.onProcessStarting(appId); |
645 | + onProcessStarting(appId); |
646 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
647 | bool authed = true; |
648 | applicationManager.authorizeSession(procId, authed); |
649 | @@ -808,7 +868,7 @@ |
650 | .WillOnce(Return(true)); |
651 | |
652 | Application *app = applicationManager.startApplication(appId); |
653 | - applicationManager.onProcessStarting(appId); |
654 | + onProcessStarting(appId); |
655 | std::shared_ptr<mir::scene::Session> session = std::make_shared<NiceMock<MockSession>>("", procId); |
656 | bool authed = true; |
657 | applicationManager.authorizeSession(procId, authed); |
658 | @@ -861,7 +921,7 @@ |
659 | .WillOnce(Return(true)); |
660 | |
661 | applicationManager.startApplication(appId); |
662 | - applicationManager.onProcessStarting(appId); |
663 | + onProcessStarting(appId); |
664 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
665 | bool authed = true; |
666 | applicationManager.authorizeSession(procId, authed); |
667 | @@ -899,7 +959,7 @@ |
668 | .WillOnce(Return(true)); |
669 | |
670 | applicationManager.startApplication(appId); |
671 | - applicationManager.onProcessStarting(appId); |
672 | + onProcessStarting(appId); |
673 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
674 | bool authed = true; |
675 | applicationManager.authorizeSession(procId, authed); |
676 | @@ -943,7 +1003,7 @@ |
677 | .WillOnce(Return(true)); |
678 | |
679 | Application *app = applicationManager.startApplication(appId); |
680 | - applicationManager.onProcessStarting(appId); |
681 | + onProcessStarting(appId); |
682 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
683 | bool authed = true; |
684 | applicationManager.authorizeSession(procId, authed); |
685 | @@ -995,7 +1055,7 @@ |
686 | .WillOnce(Return(true)); |
687 | |
688 | Application *app = applicationManager.startApplication(appId); |
689 | - applicationManager.onProcessStarting(appId); |
690 | + onProcessStarting(appId); |
691 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
692 | bool authed = true; |
693 | applicationManager.authorizeSession(procId, authed); |
694 | @@ -1042,7 +1102,7 @@ |
695 | .WillOnce(Return(true)); |
696 | |
697 | applicationManager.startApplication(appId); |
698 | - applicationManager.onProcessStarting(appId); |
699 | + onProcessStarting(appId); |
700 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
701 | bool authed = true; |
702 | applicationManager.authorizeSession(procId, authed); |
703 | @@ -1074,7 +1134,7 @@ |
704 | .WillOnce(Return(true)); |
705 | |
706 | applicationManager.startApplication(appId); |
707 | - applicationManager.onProcessStarting(appId); |
708 | + onProcessStarting(appId); |
709 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
710 | bool authed = true; |
711 | applicationManager.authorizeSession(procId, authed); |
712 | @@ -1153,7 +1213,7 @@ |
713 | .WillOnce(Return(true)); |
714 | |
715 | Application *app = applicationManager.startApplication(appId); |
716 | - applicationManager.onProcessStarting(appId); |
717 | + onProcessStarting(appId); |
718 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
719 | bool authed = true; |
720 | applicationManager.authorizeSession(procId, authed); |
721 | @@ -1206,7 +1266,7 @@ |
722 | .WillOnce(Return(true)); |
723 | |
724 | applicationManager.startApplication(appId); |
725 | - applicationManager.onProcessStarting(appId); |
726 | + onProcessStarting(appId); |
727 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
728 | bool authed = true; |
729 | applicationManager.authorizeSession(procId, authed); |
730 | @@ -1256,7 +1316,7 @@ |
731 | .WillOnce(Return(true)); |
732 | |
733 | applicationManager.startApplication(appId); |
734 | - applicationManager.onProcessStarting(appId); |
735 | + onProcessStarting(appId); |
736 | std::shared_ptr<mir::scene::Session> session1 = std::make_shared<MockSession>("", procId1); |
737 | std::shared_ptr<mir::scene::Session> session2 = std::make_shared<MockSession>("", procId2); |
738 | |
739 | @@ -1307,7 +1367,7 @@ |
740 | .WillOnce(Return(true)); |
741 | |
742 | Application *app = applicationManager.startApplication(appId); |
743 | - applicationManager.onProcessStarting(appId); |
744 | + onProcessStarting(appId); |
745 | std::shared_ptr<mir::scene::Session> session1 = std::make_shared<MockSession>("", procId1); |
746 | std::shared_ptr<mir::scene::Session> session2 = std::make_shared<MockSession>("", procId2); |
747 | |
748 | @@ -1363,7 +1423,7 @@ |
749 | .WillOnce(Return(true)); |
750 | |
751 | Application *app = applicationManager.startApplication(appId); |
752 | - applicationManager.onProcessStarting(appId); |
753 | + onProcessStarting(appId); |
754 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
755 | bool authed = true; |
756 | applicationManager.authorizeSession(procId, authed); |
757 | @@ -1394,7 +1454,7 @@ |
758 | QSignalSpy focusRequestSpy(&applicationManager, SIGNAL(focusRequested(const QString &))); |
759 | |
760 | // Upstart re-launches app |
761 | - applicationManager.onProcessStarting(appId); |
762 | + onProcessStarting(appId); |
763 | |
764 | EXPECT_EQ(Application::Starting, app->state()); |
765 | EXPECT_EQ(1, focusRequestSpy.count()); |
766 | @@ -1416,7 +1476,7 @@ |
767 | .WillOnce(Return(true)); |
768 | |
769 | auto the_app = applicationManager.startApplication(appId); |
770 | - applicationManager.onProcessStarting(appId); |
771 | + onProcessStarting(appId); |
772 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
773 | bool authed = true; |
774 | applicationManager.authorizeSession(procId, authed); |
775 | @@ -1480,7 +1540,7 @@ |
776 | .WillOnce(Return(true)); |
777 | |
778 | auto application = applicationManager.startApplication(appId); |
779 | - applicationManager.onProcessStarting(appId); |
780 | + onProcessStarting(appId); |
781 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
782 | bool authed = true; |
783 | applicationManager.authorizeSession(procId, authed); |
784 | @@ -1518,7 +1578,7 @@ |
785 | .WillOnce(Return(true)); |
786 | |
787 | applicationManager.startApplication(appId); |
788 | - applicationManager.onProcessStarting(appId); |
789 | + onProcessStarting(appId); |
790 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
791 | bool authed = true; |
792 | applicationManager.authorizeSession(procId, authed); |
793 | @@ -1558,7 +1618,7 @@ |
794 | .WillOnce(Return(true)); |
795 | |
796 | Application *the_app = applicationManager.startApplication(appId); |
797 | - applicationManager.onProcessStarting(appId); |
798 | + onProcessStarting(appId); |
799 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
800 | bool authed = true; |
801 | applicationManager.authorizeSession(procId, authed); |
802 | @@ -1603,7 +1663,7 @@ |
803 | .WillOnce(Return(true)); |
804 | |
805 | Application *the_app = applicationManager.startApplication(appId); |
806 | - applicationManager.onProcessStarting(appId); |
807 | + onProcessStarting(appId); |
808 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
809 | bool authed = true; |
810 | applicationManager.authorizeSession(procId, authed); |
811 | @@ -1674,7 +1734,7 @@ |
812 | .WillOnce(Return(true)); |
813 | |
814 | auto app = applicationManager.startApplication(appId); |
815 | - applicationManager.onProcessStarting(appId); |
816 | + onProcessStarting(appId); |
817 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
818 | bool authed = true; |
819 | applicationManager.authorizeSession(procId, authed); |
820 | @@ -1726,7 +1786,7 @@ |
821 | .WillOnce(Return(true)); |
822 | |
823 | auto app = applicationManager.startApplication(appId); |
824 | - applicationManager.onProcessStarting(appId); |
825 | + onProcessStarting(appId); |
826 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
827 | bool authed = true; |
828 | applicationManager.authorizeSession(procId, authed); |
829 | @@ -1881,7 +1941,7 @@ |
830 | .WillOnce(Return(true)); |
831 | |
832 | auto app = applicationManager.startApplication(appId); |
833 | - applicationManager.onProcessStarting(appId); |
834 | + onProcessStarting(appId); |
835 | std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
836 | bool authed = true; |
837 | applicationManager.authorizeSession(procId, authed); |
FAILED: Continuous integration, rev:427 jenkins. qa.ubuntu. com/job/ qtmir-ci/ 589/ jenkins. qa.ubuntu. com/job/ qtmir-vivid- amd64-ci/ 285/console jenkins. qa.ubuntu. com/job/ qtmir-vivid- armhf-ci/ 285/console jenkins. qa.ubuntu. com/job/ qtmir-vivid- i386-ci/ 167/console jenkins. qa.ubuntu. com/job/ qtmir-wily- amd64-ci/ 322/console jenkins. qa.ubuntu. com/job/ qtmir-wily- armhf-ci/ 322/console jenkins. qa.ubuntu. com/job/ qtmir-wily- i386-ci/ 167/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/qtmir- ci/589/ rebuild
http://