Merge lp:~gerboland/qtmir/upstart-respawning-app into lp:qtmir

Proposed by Gerry Boland
Status: Merged
Approved by: Gerry Boland
Approved revision: 256
Merged at revision: 262
Proposed branch: lp:~gerboland/qtmir/upstart-respawning-app
Merge into: lp:qtmir
Diff against target: 86 lines (+64/-1)
2 files modified
src/modules/Unity/Application/application_manager.cpp (+10/-1)
tests/modules/ApplicationManager/application_manager_test.cpp (+54/-0)
To merge this branch: bzr merge lp:~gerboland/qtmir/upstart-respawning-app
Reviewer Review Type Date Requested Status
Josh Arenson (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+235797@code.launchpad.net

Commit message

Fix AppMan handling Upstart resuming a Stopped application

AppMan did not expect apps to be restarted by anyone other than itself. However url-dispatcher will launch an instance of an application if it needs to. Should that app be in a Stopped state, AppMan would reject it. This patch has AppMan accept that new process and fire a focus event to the shell.

Description of the change

Fix AppMan handling Upstart resuming a Stopped application

 * Are there any related MPs required for this MP to build/function as expected? Please list.
N
 * Did you perform an exploratory manual test run of your code change and any related functionality?
Y
 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

To post a comment you must log in.
256. By Gerry Boland

qCDebug

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Josh Arenson (josharenson) wrote :

Reproduced the issue without the patch, and CNR with the patch. All tests pass. LGTM.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/modules/Unity/Application/application_manager.cpp'
2--- src/modules/Unity/Application/application_manager.cpp 2014-09-18 12:00:38 +0000
3+++ src/modules/Unity/Application/application_manager.cpp 2014-09-24 13:20:32 +0000
4@@ -493,7 +493,16 @@
5 Q_EMIT focusRequested(appId);
6 }
7 else {
8- qWarning() << "ApplicationManager::onProcessStarting application already found with appId" << appId;
9+ // url-dispatcher can relaunch apps which have been OOM-killed - AppMan must accept the newly spawned
10+ // application and focus it immediately (as user expects app to still be running).
11+ if (application->state() == Application::Stopped) {
12+ qCDebug(QTMIR_APPLICATIONS) << "Stopped application appId=" << appId << "is being resumed externally";
13+ application->setState(Application::Starting);
14+ Q_EMIT focusRequested(appId);
15+ } else {
16+ qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStarting application already found with appId"
17+ << appId;
18+ }
19 }
20 }
21
22
23=== modified file 'tests/modules/ApplicationManager/application_manager_test.cpp'
24--- tests/modules/ApplicationManager/application_manager_test.cpp 2014-09-18 12:00:38 +0000
25+++ tests/modules/ApplicationManager/application_manager_test.cpp 2014-09-24 13:20:32 +0000
26@@ -1787,6 +1787,60 @@
27 }
28
29 /*
30+ * Test for when a background application that has been OOM killed is relaunched by upstart.
31+ * AppMan will have the application in the app lists, in a Stopped state. Upstart will notify of
32+ * the app launching (like any normal app). Need to set the old Application instance to Starting
33+ * state and emit focusRequested to shell - authorizeSession will then associate new process with
34+ * the Application as normal.
35+ */
36+TEST_F(ApplicationManagerTests,stoppedBackgroundAppRelaunchedByUpstart)
37+{
38+ using namespace ::testing;
39+ const QString appId("testAppId");
40+ quint64 procId = 5551;
41+
42+ // Set up Mocks & signal watcher
43+ auto mockDesktopFileReader = new NiceMock<MockDesktopFileReader>(appId, QFileInfo());
44+ ON_CALL(*mockDesktopFileReader, loaded()).WillByDefault(Return(true));
45+ ON_CALL(*mockDesktopFileReader, appId()).WillByDefault(Return(appId));
46+
47+ ON_CALL(desktopFileReaderFactory, createInstance(appId, _)).WillByDefault(Return(mockDesktopFileReader));
48+
49+ EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, _))
50+ .Times(1)
51+ .WillOnce(Return(true));
52+
53+ applicationManager.startApplication(appId, ApplicationManager::NoFlag);
54+ applicationManager.onProcessStarting(appId);
55+ std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId);
56+ bool authed = true;
57+ applicationManager.authorizeSession(procId, authed);
58+ onSessionStarting(session);
59+
60+ // App creates surface, focuses it, puts it in background, then is OOM killed.
61+ std::shared_ptr<mir::scene::Surface> surface(nullptr);
62+ applicationManager.onSessionCreatedSurface(session.get(), surface);
63+ applicationManager.focusApplication(appId);
64+ applicationManager.unfocusCurrentApplication();
65+
66+ onSessionStopping(session);
67+ applicationManager.onProcessFailed(appId, false);
68+ applicationManager.onProcessStopped(appId);
69+
70+ Application *app = applicationManager.findApplication(appId);
71+ EXPECT_EQ(app->state(), Application::Stopped);
72+
73+ QSignalSpy focusRequestSpy(&applicationManager, SIGNAL(focusRequested(const QString &)));
74+
75+ // Upstart re-launches app
76+ applicationManager.onProcessStarting(appId);
77+
78+ EXPECT_EQ(app->state(), Application::Starting);
79+ EXPECT_EQ(focusRequestSpy.count(), 1);
80+ EXPECT_EQ(applicationManager.count(), 1);
81+}
82+
83+/*
84 * Test that screenshotting callback works cross thread.
85 */
86 TEST_F(ApplicationManagerTests, threadedScreenshot)

Subscribers

People subscribed via source and target branches