Merge lp:~mterry/qtmir/warn-on-xapp into lp:qtmir

Proposed by Michael Terry on 2015-12-01
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
Reviewer Review Type Date Requested Status
Unity8 CI Bot (community) continuous-integration Needs Fixing on 2016-01-13
PS Jenkins bot (community) continuous-integration Needs Fixing on 2015-12-02
Mir development team 2015-12-01 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://code.launchpad.net/~mterry/unity8/warn-on-xapp/+merge/277915
 https://code.launchpad.net/~mterry/ubuntu-app-launch/warn-on-xapp/+merge/279323
 https://code.launchpad.net/~mterry/unity-api/warn-on-xapp/+merge/277922

To post a comment you must log in.
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://unity8-jenkins.ubuntu.com/job/lp-qtmir-1-ci/5/
Executed test runs:

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtmir-1-ci/5/rebuild

review: Needs Fixing (continuous-integration)
lp:~mterry/qtmir/warn-on-xapp updated on 2016-05-17
428. By Michael Terry on 2016-05-16

Merge from trunk; disabled actual hooks for signals, will fix later

429. By Michael Terry on 2016-05-16

Go back to checking start return value

430. By Michael Terry on 2016-05-17

Start porting to app object signals, still won't work

431. By Michael Terry on 2016-05-17

remove some unused code from a bad merge

Unmerged revisions

431. By Michael Terry on 2016-05-17

remove some unused code from a bad merge

430. By Michael Terry on 2016-05-17

Start porting to app object signals, still won't work

429. By Michael Terry on 2016-05-16

Go back to checking start return value

428. By Michael Terry on 2016-05-16

Merge from trunk; disabled actual hooks for signals, will fix later

427. By Michael Terry on 2015-12-01

Remove/delete app if it is denied, so that its internal state doesn't hang around

426. By Michael Terry on 2015-12-01

Update to handle latest unity-api branch

425. By Michael Terry on 2015-12-01

Merge from trunk

424. By Michael Terry on 2015-12-01

Initial cut of supporting app starting approval api in ubuntu-app-launch

423. By Michael Terry on 2015-11-30

Merge more-accurate-mocks

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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);

Subscribers

People subscribed via source and target branches