Merge lp:~dandrader/qtmir/appRestart-lp1527737 into lp:qtmir
- appRestart-lp1527737
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~dandrader/qtmir/appRestart-lp1527737 |
Merge into: | lp:qtmir |
Prerequisite: | lp:~dandrader/qtmir/initialSurfaceGeom |
Diff against target: |
706 lines (+315/-85) 10 files modified
src/modules/Unity/Application/application_manager.cpp (+81/-61) src/modules/Unity/Application/application_manager.h (+1/-1) src/modules/Unity/Application/mirsurfacelistmodel.cpp (+21/-0) src/modules/Unity/Application/mirsurfacelistmodel.h (+2/-0) src/modules/Unity/Application/session.cpp (+21/-22) src/modules/Unity/Application/taskcontroller.h (+5/-1) src/modules/Unity/Application/upstart/taskcontroller.cpp (+8/-0) src/modules/Unity/Application/upstart/taskcontroller.h (+2/-0) tests/framework/mock_task_controller.h (+1/-0) tests/modules/ApplicationManager/application_manager_test.cpp (+173/-0) |
To merge this branch: | bzr merge lp:~dandrader/qtmir/appRestart-lp1527737 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gerry Boland (community) | Needs Fixing | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Unity8 CI Bot (community) | continuous-integration | Needs Fixing | |
Michał Sawicz | Pending | ||
Review via email: mp+284640@code.launchpad.net |
This proposal supersedes a proposal from 2016-01-05.
Commit message
Handle case where TaskController requests an application that is already closing
Happens when you quickly close an application and then tap on its icon in the dash
Description of the change
* Are there any related MPs required for this MP to build/function as expected? Please list.
Not strictly needed but I haven't tried without it:
https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes, on phone and desktop.
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Not applicable.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:437
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
=== modified file 'src/modules/
+ // We interpret this as a focus request for a suspended app.
+ // Shell will have this app resumed if it complies with the focus request
QObject:
- manager, &ApplicationMan
+ manager, &ApplicationMan
The original purpose of the resumeRequested signal from UAL was to tell AppMan to un-suspend a suspended app, since AppMan used to manage that. But since UAL does suspend/resume now itself, this signal is worthless. Suspect we should remove completely.
Does not the focusRequested signal always get fired if url-dispatcher wants to focus an app? In which case, is this interpretation even necessary? If we can, I think we should remove it.
+ << "ApplicationMan
+ " a new instance of an application that is still closing. Queuing its start.";
we should investigate how to launch new instance immediately, instead of waiting for the closing one to quit. I'd be worried if the closing app crashes during close, as it won't be considered closed until apport has completed collecting the crash dump, causing the new instance a long delay. Not for this MP, but perhaps a TODO?
Also nitpick: could you line up the qCDebug strings, in both spots in this method?
+ // TaskController doesn't give us any PID so we have no way of telling apart two instances
+ // of an application.
we should get that fixed. UAL must have way of dealing with multiple instances of the same App, and distinguishing them. If not, we'll need to add it.
+1 on the header for the test. We should do that from now on.
+ // DeferredDelete is special: likes to be called out specifically or it won't come out
weird?? Event loop blocked somehow?
Nice work
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:438
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:440
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
On 07/01/2016 14:39, Gerry Boland wrote:
> Review: Needs Fixing
>
> === modified file 'src/modules/
> + // We interpret this as a focus request for a suspended app.
> + // Shell will have this app resumed if it complies with the focus request
> QObject:
> - manager, &ApplicationMan
> + manager, &ApplicationMan
>
>
> The original purpose of the resumeRequested signal from UAL was to tell AppMan to un-suspend a suspended app, since AppMan used to manage that. But since UAL does suspend/resume now itself, this signal is worthless. Suspect we should remove completely.
>
> Does not the focusRequested signal always get fired if url-dispatcher wants to focus an app? In which case, is this interpretation even necessary? If we can, I think we should remove it.
When you tap on a suspended app in the dash you immediately get a
appStarting followed by a resumeRequest. If you don't respond to it (ie,
resume&focus the app), ages later you get a focusRequested.
So if I remove resumeRequested I would have to interpret appStarting for
a already running application as a focus request, which actually
wouldn't be wrong.
Btw, I find it odd that ubuntu_app_launch work that way, always sending
an appStarting signal even though the app is already running, but that's
the way it is...
> + << "ApplicationMan
> + " a new instance of an application that is still closing. Queuing its start.";
> we should investigate how to launch new instance immediately, instead of waiting for the closing one to quit. I'd be worried if the closing app crashes during close, as it won't be considered closed until apport has completed collecting the crash dump, causing the new instance a long delay. Not for this MP, but perhaps a TODO?
Agreed. The delay is noticeable. Added the TODO comment.
>
> Also nitpick: could you line up the qCDebug strings, in both spots in this method?
Wrapped the qCDebug boilerplate in a macro.
>
>
> + // TaskController doesn't give us any PID so we have no way of telling apart two instances
> + // of an application.
> we should get that fixed. UAL must have way of dealing with multiple instances of the same App, and distinguishing them. If not, we'll need to add it.
As far as I understand it ubuntu-app-launch (and the upstart service?)
have the concept that you can have only one running instance of an
application (like a service, that you start/stop using upstart).
This sounds like a bigger architectural change, out of scope for this MP.
> + // DeferredDelete is special: likes to be called out specifically or it won't come out
> weird?? Event loop blocked somehow?
>
QObject:
in a special way in QCoreApplication etc, unlike any other QEvent.
There's code in there specifically for leaving it out of forced event
processing (like sendPostedEvents) unless you explicitly ask for that
particular event type.
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
> On 07/01/2016 14:39, Gerry Boland wrote:
> > Review: Needs Fixing
> >
> > === modified file 'src/modules/
> > + // We interpret this as a focus request for a suspended app.
> > + // Shell will have this app resumed if it complies with the focus
> request
> > QObject:
> > - manager, &ApplicationMan
> > + manager, &ApplicationMan
> >
> >
> > The original purpose of the resumeRequested signal from UAL was to tell
> AppMan to un-suspend a suspended app, since AppMan used to manage that. But
> since UAL does suspend/resume now itself, this signal is worthless. Suspect we
> should remove completely.
> >
> > Does not the focusRequested signal always get fired if url-dispatcher wants
> to focus an app? In which case, is this interpretation even necessary? If we
> can, I think we should remove it.
>
> When you tap on a suspended app in the dash you immediately get a
> appStarting followed by a resumeRequest. If you don't respond to it (ie,
> resume&focus the app), ages later you get a focusRequested.
>
> So if I remove resumeRequested I would have to interpret appStarting for
> a already running application as a focus request, which actually
> wouldn't be wrong.
>
> Btw, I find it odd that ubuntu_app_launch work that way, always sending
> an appStarting signal even though the app is already running, but that's
> the way it is...
Fair enough. This will do for now.
>
> >
> >
> > + // TaskController doesn't give us any PID so we have no way of telling
> apart two instances
> > + // of an application.
> > we should get that fixed. UAL must have way of dealing with multiple
> instances of the same App, and distinguishing them. If not, we'll need to add
> it.
>
> As far as I understand it ubuntu-app-launch (and the upstart service?)
> have the concept that you can have only one running instance of an
> application (like a service, that you start/stop using upstart).
>
> This sounds like a bigger architectural change, out of scope for this MP.
Oh of course. Was just observation.
> > + // DeferredDelete is special: likes to be called out specifically or it
> won't come out
> > weird?? Event loop blocked somehow?
> >
>
> QObject:
> in a special way in QCoreApplication etc, unlike any other QEvent.
> There's code in there specifically for leaving it out of forced event
> processing (like sendPostedEvents) unless you explicitly ask for that
> particular event type.
Interesting, I didn't know that.
Gerry Boland (gerboland) wrote : Posted in a previous version of this proposal | # |
Just ran UITK AP tests to ensure sanity, no issues found. Happy to approve
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal | # |
QA found a problem with this and I can confirm on devel-proposed/
Trying to follow steps from Victor [1] I got into a state where unity8 rejects the camera app:
qtmir.applications: ApplicationMana
qtmir.mir: SessionAuthoriz
qtmir.applications: ApplicationMana
ApplicationManager REJECTED connection from app with pid 22192 as it was not launched by upstart, and no desktop_file_hint is specified
qtmir.applications: ApplicationMana
qtmir.applications: ApplicationMana
Victor can confirm the same happened to him with camera and settings apps.
[1] https:/
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
On 12/01/2016 14:39, Michał Sawicz wrote:
> Review: Needs Fixing
>
> QA found a problem with this and I can confirm on devel-proposed/
>
> Trying to follow steps from Victor [1] I got into a state where unity8 rejects the camera app:
>
> qtmir.applications: ApplicationMana
> qtmir.mir: SessionAuthoriz
> qtmir.applications: ApplicationMana
> ApplicationManager REJECTED connection from app with pid 22192 as it was not launched by upstart, and no desktop_file_hint is specified
> qtmir.applications: ApplicationMana
> qtmir.applications: ApplicationMana
>
> Victor can confirm the same happened to him with camera and settings apps.
>
> [1] https:/
I followed the steps below:
"""
* Open messaging app.
* Slide up to create a new message.
* Tap on the camera icon.
* In content hub tap on the camera app.
* Take a photo in the camera app.
* Tap on the big tick. Returned to the messaging app with the image in
the text window.
* Swipe in from the right to reveal the spread.
* Open spread.
* Switch to the camera app.
Expected result:
* Camera app should display the live view.
Actual result:
* Camera app shows a black screen
"""
A second after switching to camera-app it goes away.
Log shows that camera-app quit (closed itself). Which is expected as it
was summoned by the content hub as a helper and was no longer needed.
Different from the log you got.
In this situation there's nothing unity8 can do. If the app closes
itself shortly after it's focused, I don't think unity8 should go and
restart it.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
Furthermore, in this "messaging -> content-hub -> camera-app" use case, unity8 is *not* asking camera-app to close itself, unlike the use case of the bug report which is what this MP is fixing.
From unity8's point of view, camera-app is simply quitting on its own accord.
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
it probably shouldn't even be in the spread in the first place, like if it were a surface from a prompt helper session.
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal | # |
Then you didn't get the issue I described. There are no reliable steps to reproduce, but after I followed those steps (and camera crashed due to bug #1524131, I couldn't start camera at all after it closed. The above messages were printed in unity8's log, not how it says that camera was not started by upstart and that's why it's rejected. But camera was, in fact, started by upstart, from the apps scope. Victor reported this same problem with settings app, so unrelated to content hub. I've not seen it happen without this change.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:440
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Daniel d'Andrada (dandrader) wrote : Posted in a previous version of this proposal | # |
I just can't reproduce it. I'm stuck. Added the handling of a special case though, where upstart would send a bogus signal.
Could you please install the latest version of this patch + lp:~dandrader/qtubuntu/offscreenSurface-lp1527737 and then send me the log of this failure? Ah, and not just the last few lines!
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:441
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:441
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal | # |
Eh, you'll need to rebase this one, too...
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:444
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:444
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 439. By Nick Dedekind
-
Added fix and test for closing app during the StoppedResumable state. Fixes: #1541388
Approved by: Michael Zanetti - 440. By CI Train Bot Account
-
Releasing 0.4.7+16.
04.20160208- 0ubuntu1 - 441. By Nick Dedekind
-
Moved test framework into a static library for quicker recompilation.
Approved by: Gerry Boland - 442. By Daniel d'Andrada
-
Remove the useless TaskController
It was just forwarding calls between ApplicationManager and ApplicationCron
troller.
Had no logic of its own.ApplicationCron
troller was then renamed to TaskController as the latter has a better API and it also keeps ApplicationManager code more or less untouched. Tests have been improved a bit by better emulating TaskController behavior
Approved by: Nick Dedekind - 443. By Daniel d'Andrada
-
Let shell decide the initial surface size Fixes: #1532974
Approved by: Nick Dedekind - 444. By Daniel d'Andrada
-
Surface Size Hints
Approved by: Lukáš Tinkl - 445. By Albert Astals Cid
-
Reset start time if the timestamp travels to the past
Fixes: #1524488
Approved by: Nick Dedekind - 446. By Albert Astals Cid
-
Provide branch prediction information to the if in compressTimestamp
Approved by: Gerry Boland - 447. By Michał Sawicz
-
Use QStandardPaths to determine QML cache location
Also use temporary XDG_CACHE_HOME in ApplicationMana
gerTests so we don't pollute user's $HOME
Approved by: Unity8 CI Bot, Albert Astals Cid - 448. By Daniel d'Andrada
-
Update mir version requirement
Approved by: Nick Dedekind - 449. By Michał Sawicz
-
Bump unity-api dependencies
Approved by: Michael Terry - 450. By CI Train Bot Account
-
Releasing 0.4.7+16.
04.20160212- 0ubuntu1 - 451. By Alan Griffiths
-
Mir 0.20 Release
Approved by: Cemil Azizoglu - 452. By CI Train Bot Account
-
Releasing 0.4.7+16.
04.20160219- 0ubuntu1
Gerry Boland (gerboland) wrote : | # |
/me picks this up again. Will see what light I can shed on the thing QA found
Gerry Boland (gerboland) wrote : | # |
Eep, lots of conflicts with trunk
Gerry Boland (gerboland) wrote : | # |
I fixed conflicts here: lp:~gerboland/qtmir/appRestart-lp1527737-rebased save you the trouble
Daniel d'Andrada (dandrader) wrote : | # |
On 08/03/2016 12:15, Gerry Boland wrote:
> I fixed conflicts here: lp:~gerboland/qtmir/appRestart-lp1527737-rebased save you the trouble
Dednick had some hot fixes on problems similar to this one recently.
Which makes me think how relevant this MP still is (haven't spent any
time perusing it though).
And I also made a lot of changes in lifecycle code in the surface-based
window management work. If we want to proceed with this MP I would
rather put it on top of the surface WM work. It's like a whole new world
(surface-based versus application/
- 453. By Gerry Boland
-
Allow Mir remove command line arguments it understands, before letting Qt process them.
Approved by: Daniel d'Andrada - 454. By Alan Griffiths
-
Copy the Window Management work-in-progress from Mir examples.
Approved by: Gerry Boland - 455. By Michael Zanetti
-
Add a dedicated property for the inputMethodSurface
When we're hot-plugging screens, the OSK ui might only be created after surfaceCreated() is emitted and we miss that signal. Fixes: #1545286
Approved by: Daniel d'Andrada - 456. By Gerry Boland
-
Screen: only enable orientation sensor for internal display.
It's not great, but works around orientation sensor not working after device unplug from monitor. I believe this is because QtUbuntu-Sensors and Platform-api are not dealing properly with multiple accessors of the sensors. Instead only the last accessor gets correct state, and the earlier ones get nothing. Fixes: #1545286
Approved by: Unity8 CI Bot, Michael Zanetti - 457. By Daniel d'Andrada
-
Ensure QmlEngine doesn't delete our MirSurfaces
Approved by: Gerry Boland, Unity8 CI Bot - 458. By Gerry Boland
-
Ensure ScreenWindow geometry correctly set and used after moving Screen
NB: this will conflict with lp:~unity-team/qtmir/set-display-config, from which this is a cherry-pick Fixes: #1545286
Approved by: Gerry Boland, Unity8 CI Bot - 459. By Michael Terry
-
Fix some mocks to use more realistic code paths.
Specifically, MockApplication
Controller: :doAppIdHasProc essId() was returning -1 if the appId was unknown. But that function returns a bool, so the -1 got translated into a true value. So that mocked method returned true for appIds that hadn't been registered yet. In order to fix that, I decided to rewrite doAppIdHasProcessId to call primaryPidForAppId so that it could be overridden easier in tests. And adjusted the affected tests to all set an ON_CALL(
primaryPidForAp pId). (Because otherwise the test has no way to influence the pid used for children -- why do we actually fork off a while(true) process?)
There are several other fixes here for pieces of the mocks that I found were missing while exploring solutions for the above problem:
- I'm actually not 100% clear on why this started being called, but MockSession::name() couldn't create a default value for QString and the gtest framework was bailing when it was called. So I added a default.
- Similarly, if ApplicationMana
ger::authorizeS ession( ) tries to examine an app's commandline, gtest will abort because MockProcInfo: :command_ line() doesn't have a mock return value. So I added a default. - And if authorizeSession() lasted long enough to see that the Application object already existed, it deleted the desktop reader object it had made. But the test mocks always returned the same object, so this caused a segfault. I retooled the ApplicationManager tests to return a new object each time DesktopFileRead
erFactory: :createInstance was called.
Approved by: Gerry Boland, Unity8 CI Bot - 460. By Alberto Aguirre
-
Hook MirOpenGLContex
t::doneCurrent to Screen::doneCurrent Actually unbind the opengl/egl context when requested.
Approved by: Gerry Boland - 461. By Michał Sawicz
-
Drop dummy autopkgtest
It doesn't make sense after all - DEP-8 tests are meant to test packages as-installed, not rebuild them from scratch. This meant that new Mir releases got blocked on this, because old qtmir was trying to build against new Mir, which usually fails, as needs adaptation for API changes.
Approved by: Gerry Boland - 462. By CI Train Bot Account
-
Releasing 0.4.7+16.
04.20160310. 1-0ubuntu1 - 463. By Nick Dedekind
-
Added setStage for sidestage redesign and removed ExecFlags
Approved by: Daniel d'Andrada - 464. By Michał Sawicz
-
Add support for low shell chrome. Fixes: #1535397
Approved by: Gerry Boland - 465. By Michał Sawicz
-
Support for switching keyboard layouts Fixes: #1491340, #1524400
Approved by: Michael Terry - 466. By CI Train Bot Account
-
Releasing 0.4.8+16.
04.20160322. 1-0ubuntu1 - 467. By Daniel van Vugt
-
Don't use preferred_
mode_index. Some devices like TVs don't provide a
preferred mode, so preferred_mode_index may be out of range (a clumsy
way to represent 'none'). Instead use the resolution of the current display mode, which should always be in range.Fixes LP: #1560497 Fixes: #1560497
Approved by: Gerry Boland - 468. By CI Train Bot Account
-
Releasing 0.4.8+16.
04.20160329. 1-0ubuntu1 - 469. By Michał Sawicz
-
Drop leftover Xs-Testsuite header
Approved by: Unity8 CI Bot, Gerry Boland - 470. By CI Train Bot Account
-
Releasing 0.4.8+16.
04.20160330- 0ubuntu1 - 471. By Daniel d'Andrada
-
Logging of Qt's OpenGL debug messages now must be enabled via CMake option
Approved by: Gerry Boland - 472. By Daniel d'Andrada
-
Application: improve debug logging
Minimize boilerplate in logging code, as well as standardise its format.
Approved by: Gerry Boland - 473. By Daniel d'Andrada
-
Remove application screenshot provider
It's no longer needed now that QML provides a "item-snapshot" feature.
Besides, it has no purpose in a surface-based window management.
Approved by: Lukáš Tinkl, Gerry Boland - 474. By Daniel d'Andrada
-
MirSurface: replace keymapLayout and keymapVariant with keymap
That's easier for unity8 to use, leads to declarative code.
Approved by: Lukáš Tinkl - 475. By Daniel d'Andrada
-
Surface-based window management
- Session is no longer exported to QML. It's now an internal qtmir concept.
Approved by: Gerry Boland - 476. By Michał Sawicz
-
Inline -gles packaging.
Approved by: Gerry Boland - 477. By CI Train Bot Account
-
Releasing 0.4.8+16.
04.20160413- 0ubuntu1 - 478. By Alberto Aguirre
-
Mir 0.22 compatibility
Approved by: Cemil Azizoglu, Kevin DuBois, Brandon Schaefer - 479. By CI Train Bot Account
-
Releasing 0.4.8+16.
04.20160426- 0ubuntu1 - 480. By Michael Terry
-
Use latest UbuntuAppLaunch API which supports libertine apps.
Approved by: Nick Dedekind - 481. By Lukáš Tinkl
-
Regression fix: restore window title handling Fixes: #1563522
Approved by: Nick Dedekind - 482. By CI Train Bot Account
-
Releasing 0.4.8+16.
04.20160428- 0ubuntu1 - 483. By Gerry Boland
-
Enhance ScreenController & the DisplayConfigur
ationPolicy to implement dynamic grid units. - Rename ScreenController to ScreenModel, as it just reflects current screen state, does not offer means to configure it
- ScreenController can update state of existing Screens, based on Mir DisplayConfiguration changes.
- Expand Screen to include scale & form factor properties, with getter/notifier in NativeInterface. This enables the dynamic grid units in the shell
- Add a Unity.Screens qml module to give QML better information about connected screens, and allow basic reconfiguring.
- Implement a basic display configuration policy to set suitable scale and form factor on an external display (needed for dynamic grid units) Fixes: #1573532
Approved by: Unity8 CI Bot, Daniel d'Andrada - 484. By CI Train Bot Account
-
Releasing 0.4.8+16.
04.20160429. 1-0ubuntu1 - 485. By Daniel d'Andrada
-
Session: Add a blank surface to the public list if it already has child prompt surfaces
A prompt session may come in too early, before its parent session got a chance
to draw its surface's first frame.Normally that wouldn't be a problem and we could withhold that parent surface until
it's finally drawn to. But unfortunately the application process might be blocked,
unable to draw anything, until its child prompt session gets dismissed.Because of that we have no option but to expose this blank surface to shell so that
it can display it along with the prompt surface on top of it, so that the user can
interact with it right away and finally unblock the application. Fixes: #1578665
Approved by: Unity8 CI Bot - 486. By CI Train Bot Account
-
Releasing 0.4.8+16.
04.20160511- 0ubuntu1 - 487. By Daniel d'Andrada
-
Fix ProxySurfaceLis
tModel: :countChanged signal
Approved by: Unity8 CI Bot - 488. By Daniel d'Andrada
-
Move prompt surfaces from MirSurface to Application and emit firstChanged signal
- 489. By CI Train Bot Account
-
Releasing 0.4.8+16.
04.20160518. 1-0ubuntu1 - 490. By Gerry Boland
-
UAL can throw on creating Application if invalid appId, catch instead of aborting Fixes: #1578258
Approved by: Unity8 CI Bot, Michael Terry - 491. By Daniel d'Andrada
-
Application: Don't respawn if closed while still starting up
+ refactoring of Application:
:onSessionState Changed to explicitly cover every single internal state on session stopping. Fixes: #1575577
Approved by: Gerry Boland, Unity8 CI Bot, Michael Terry - 492. By Alan Griffiths
-
Reduce coupling to MirServer - it has been misused as a context object.
Approved by: Alan Griffiths, Unity8 CI Bot, Daniel d'Andrada - 493. By Michał Sawicz
-
Centralize logging categories
The header part is already centralized. Make the cpp the same.
Moves all logging category symbols to the mirserver lib.
Enables mirserver to use logging categories that were previously declared in the Unity.Application module.
Approved by: Unity8 CI Bot, Michael Terry - 494. By Daniel d'Andrada
-
Also interpret the cursor names used by Mir client API Fixes: #1447839
Approved by: Unity8 CI Bot, Michał Sawicz - 495. By Timo Jyrinki
-
Use FindQt5Platform
Support to find platform support, other methods not available on Qt 5.6 anymore. Fixes: #1554404
Approved by: Gerry Boland - 496. By CI Train Bot Account
-
Releasing 0.4.8+16.
10.20160520. 1-0ubuntu1 - 497. By Daniel d'Andrada
-
Bump unity-api versions
Approved by: Lukáš Tinkl - 498. By Alan Griffiths
-
Drop the (unused) prototype Window Management code
Approved by: Gerry Boland, Unity8 CI Bot - 499. By Daniel d'Andrada
-
Fix mir::scene::Surface focus attribute updates
Approved by: Unity8 CI Bot - 500. By Albert Astals Cid
-
Enable workaround_
brokenFBOReadBa ck on various chipsets Gives for impressive improvements in QSGDefaultDista
nceFieldGlyphCa che::storeGlyph s
impressive = 788ms -> 6msCopied from qtubuntu
Fixes: #1581123
Approved by: Gerry Boland, Unity8 CI Bot - 501. By Alan Griffiths
-
Remove workaround for lp:1502200
Approved by: Unity8 CI Bot, Daniel d'Andrada - 502. By CI Train Bot Account
-
Releasing 0.4.8+16.
10.20160525. 2-0ubuntu1 - 503. By Kevin DuBois
-
rebuild for mir 0.23
- 504. By CI Train Bot Account
-
Releasing 0.4.8+16.
10.20160602- 0ubuntu1 - 505. By Michael Zanetti
-
Adding ApplicationInfo
::surfaceCount property - 506. By Albert Astals Cid
-
Add support for compiler sanitizers via ECM
- 507. By Albert Astals Cid
-
Compile with -fsanitize=
undefined - 508. By Albert Astals Cid
-
Fix leak in ScreensModelTest (LP: #1585502)
- 509. By Albert Astals Cid
-
Fix leak in SessionManager test (LP: #1585498)
- 510. By Albert Astals Cid
-
Remove unused m_sessions member
- 511. By Albert Astals Cid
-
Add missing breaks
- 512. By Albert Astals Cid
-
Initialize m_lastX and m_lastY
- 513. By Albert Astals Cid
-
Initialize m_sessionId
- 514. By Albert Astals Cid
-
Give the locker a name
- 515. By Albert Astals Cid
-
Fix memory leak in QtEventFeederTest (LP: #1585503)
- 516. By Albert Astals Cid
-
Fix leaks in application_
manager_ test (LP: #1585501) - 517. By Daniel d'Andrada
-
Improve Session debug logging
- 518. By Daniel d'Andrada
-
MirSurfaceListM
odel: prepending a surface always causes firstChanged() emission - 519. By Gerry Boland
-
Release temporary GL context ASAP, fixes QtMir on X11. Add some hotpath branching hints (LP: #1588921)
- 520. By CI Train Bot Account
-
Releasing 0.4.8+16.
10.20160614- 0ubuntu1 - 521. By Daniel d'Andrada
-
Handle case where TaskController requests an application that is already closing
Happens when you quickly close an application and then tap on its icon in the dash
- 522. By Daniel d'Andrada
-
Optimize code
- 523. By Daniel d'Andrada
-
Fix bad rebase on top of latest trunk
Code was still using the old, deprecated signal.
Unmerged revisions
- 523. By Daniel d'Andrada
-
Fix bad rebase on top of latest trunk
Code was still using the old, deprecated signal.
- 522. By Daniel d'Andrada
-
Optimize code
- 521. By Daniel d'Andrada
-
Handle case where TaskController requests an application that is already closing
Happens when you quickly close an application and then tap on its icon in the dash
Preview Diff
1 | === modified file 'src/modules/Unity/Application/application_manager.cpp' |
2 | --- src/modules/Unity/Application/application_manager.cpp 2016-05-06 08:41:15 +0000 |
3 | +++ src/modules/Unity/Application/application_manager.cpp 2016-06-16 20:19:32 +0000 |
4 | @@ -56,6 +56,8 @@ |
5 | namespace unityapi = unity::shell::application; |
6 | |
7 | #define DEBUG_MSG qCDebug(QTMIR_APPLICATIONS).nospace() << "ApplicationManager::" << __func__ |
8 | +#define WARNING_MSG qCWarning(QTMIR_APPLICATIONS).nospace() << "ApplicationManager::" << __func__ |
9 | +#define CRITICAL_MSG qCCritical(QTMIR_APPLICATIONS).nospace() << "ApplicationManager::" << __func__ |
10 | |
11 | namespace qtmir |
12 | { |
13 | @@ -102,8 +104,10 @@ |
14 | manager, &ApplicationManager::onProcessFailed); |
15 | QObject::connect(controller, &TaskController::focusRequested, |
16 | manager, &ApplicationManager::onFocusRequested); |
17 | + // We interpret this as a focus request for a suspended app. |
18 | + // Shell will have this app resumed if it complies with the focus request |
19 | QObject::connect(controller, &TaskController::resumeRequested, |
20 | - manager, &ApplicationManager::onResumeRequested); |
21 | + manager, &ApplicationManager::onFocusRequested); |
22 | } |
23 | |
24 | } // namespace |
25 | @@ -368,35 +372,61 @@ |
26 | void ApplicationManager::onProcessStarting(const QString &appId) |
27 | { |
28 | tracepoint(qtmir, onProcessStarting); |
29 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStarting - appId=" << appId; |
30 | - |
31 | - Application *application = findApplication(appId); |
32 | - if (!application) { // then shell did not start this application, so ubuntu-app-launch must have - add to list |
33 | - auto appInfo = m_taskController->getInfoForApp(appId); |
34 | - if (!appInfo) { |
35 | - qCWarning(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStarting - Unable to instantiate application with appId" << appId; |
36 | - return; |
37 | - } |
38 | - |
39 | - application = new Application( |
40 | - m_sharedWakelock, |
41 | - appInfo, |
42 | - QStringList(), |
43 | - this); |
44 | - add(application); |
45 | - application->requestFocus(); |
46 | - } |
47 | - else { |
48 | - if (application->internalState() == Application::InternalState::StoppedResumable) { |
49 | - // url-dispatcher can relaunch apps which have been OOM-killed - AppMan must accept the newly spawned |
50 | - // application and focus it immediately (as user expects app to still be running). |
51 | - qCDebug(QTMIR_APPLICATIONS) << "Stopped application appId=" << appId << "is being resumed externally"; |
52 | - application->requestFocus(); |
53 | - } else { |
54 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStarting application already found with appId" |
55 | - << appId; |
56 | - } |
57 | - } |
58 | + |
59 | + Application *application = nullptr; |
60 | + |
61 | + application = findClosingApplication(appId); |
62 | + if (application) { |
63 | + // TODO: We should create a new Application instance right away in order to give immediate |
64 | + // feedback to the user, even though there's no actual process backing it up yet. |
65 | + if (!m_queuedStartApplications.contains(appId)) { |
66 | + m_queuedStartApplications.append(appId); |
67 | + DEBUG_MSG << "(" << appId << ") User wants to start a new instance of an application that is still closing." |
68 | + " Queuing its start."; |
69 | + connect(application, &QObject::destroyed, this, [this, appId]() { |
70 | + m_queuedStartApplications.removeAll(appId); |
71 | + startApplication(appId, QStringList()); |
72 | + }, Qt::QueuedConnection); // Queued so that we finish the app removal before starting again. |
73 | + } else { |
74 | + // Just ignore it. |
75 | + DEBUG_MSG << "(" << appId << ") User wants to start a new instance of an application that is still closing" |
76 | + " and is already queued to start later."; |
77 | + } |
78 | + } else { |
79 | + application = findApplication(appId); |
80 | + if (!application) { // then shell did not start this application, so ubuntu-app-launch must have - add to list |
81 | + createNewApplication(appId); |
82 | + } else { |
83 | + if (application->internalState() == Application::InternalState::StoppedResumable) { |
84 | + // url-dispatcher can relaunch apps which have been OOM-killed - AppMan must accept the newly spawned |
85 | + // application and focus it immediately (as user expects app to still be running). |
86 | + DEBUG_MSG << "(" << appId << ") Stopped application is being resumed externally"; |
87 | + application->requestFocus(); |
88 | + } else { |
89 | + DEBUG_MSG << "(" << appId << ") application already exists"; |
90 | + } |
91 | + application->setProcessState(Application::ProcessRunning); |
92 | + } |
93 | + } |
94 | +} |
95 | + |
96 | +void ApplicationManager::createNewApplication(const QString &appId) |
97 | +{ |
98 | + DEBUG_MSG << "(" << appId << ")"; |
99 | + |
100 | + auto appInfo = m_taskController->getInfoForApp(appId); |
101 | + if (!appInfo) { |
102 | + WARNING_MSG << "(" << appId << ") Unable to instantiate application"; |
103 | + return; |
104 | + } |
105 | + |
106 | + auto application = new Application( |
107 | + m_sharedWakelock, |
108 | + appInfo, |
109 | + QStringList(), |
110 | + this); |
111 | + add(application); |
112 | + application->requestFocus(); |
113 | application->setProcessState(Application::ProcessRunning); |
114 | } |
115 | |
116 | @@ -412,7 +442,7 @@ |
117 | |
118 | Application *application = findApplication(appId); |
119 | if (!application) { |
120 | - qCritical() << "No such running application with appId" << appId; |
121 | + CRITICAL_MSG << "(" << inputAppId << ") No such running application"; |
122 | return false; |
123 | } |
124 | |
125 | @@ -454,14 +484,18 @@ |
126 | tracepoint(qtmir, onProcessStopped); |
127 | qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStopped - appId=" << appId; |
128 | |
129 | - Application *application = findApplication(appId); |
130 | + // TaskController doesn't give us any PID so we have no way of telling apart two instances |
131 | + // of an application. |
132 | + // The only situation where we expect to have two simultaneous instances is where there's one |
133 | + // closing and a newer one just starting, in which case we assume he's referring to the former. |
134 | + Application *application = findClosingApplication(appId); |
135 | if (!application) { |
136 | - application = findClosingApplication(appId); |
137 | + application = findApplication(appId); |
138 | } |
139 | |
140 | if (!application) { |
141 | - qDebug() << "ApplicationManager::onProcessStopped reports stop of appId=" << appId |
142 | - << "which AppMan is not managing, ignoring the event"; |
143 | + // Might happen if the onProcessFailed() was called for this app and it already got deleted in response. |
144 | + DEBUG_MSG << "(" << appId << ") Not managing it, ignoring."; |
145 | return; |
146 | } |
147 | |
148 | @@ -490,29 +524,15 @@ |
149 | |
150 | void ApplicationManager::onFocusRequested(const QString& appId) |
151 | { |
152 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onFocusRequested - appId=" << appId; |
153 | - |
154 | - Application *application = findApplication(appId); |
155 | - if (application) { |
156 | - application->requestFocus(); |
157 | - } |
158 | -} |
159 | - |
160 | -void ApplicationManager::onResumeRequested(const QString& appId) |
161 | -{ |
162 | - qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onResumeRequested - appId=" << appId; |
163 | - |
164 | - Application *application = findApplication(appId); |
165 | - |
166 | - if (!application) { |
167 | - qCritical() << "ApplicationManager::onResumeRequested: No such running application" << appId; |
168 | - return; |
169 | - } |
170 | - |
171 | - // We interpret this as a focus request for a suspended app. |
172 | - // Shell will have this app resumed if it complies with the focus request |
173 | - if (application->state() == Application::Suspended) { |
174 | - application->requestFocus(); |
175 | + Application *application = findApplication(appId); |
176 | + |
177 | + if (m_queuedStartApplications.contains(appId) || findClosingApplication(appId) != nullptr) { |
178 | + DEBUG_MSG << "(" << appId << ") Ignoring request as the application is closing and/or queued to start"; |
179 | + } else if (application) { |
180 | + DEBUG_MSG << "(" << appId << ") Emitting focusRequested"; |
181 | + Q_EMIT focusRequested(appId); |
182 | + } else { |
183 | + WARNING_MSG << "(" << appId << ") No such running application"; |
184 | } |
185 | } |
186 | |
187 | @@ -702,9 +722,9 @@ |
188 | |
189 | connect(application, &Application::stopProcessRequested, this, [=]() { |
190 | if (!m_taskController->stop(appId) && application->pid() > 0) { |
191 | - qWarning() << "FAILED to ask Upstart to stop application with appId" << appId |
192 | - << "Sending SIGTERM to process:" << appId; |
193 | - kill(application->pid(), SIGTERM); |
194 | + qCWarning(QTMIR_APPLICATIONS) << "FAILED to ask Upstart to stop application with appId" << appId |
195 | + << "Sending SIGTERM to process"; |
196 | + m_taskController->kill(application->pid()); |
197 | application->setProcessState(Application::ProcessStopped); |
198 | } |
199 | }); |
200 | |
201 | === modified file 'src/modules/Unity/Application/application_manager.h' |
202 | --- src/modules/Unity/Application/application_manager.h 2016-05-05 15:02:01 +0000 |
203 | +++ src/modules/Unity/Application/application_manager.h 2016-06-16 20:19:32 +0000 |
204 | @@ -111,7 +111,6 @@ |
205 | void onProcessSuspended(const QString& appId); |
206 | void onProcessFailed(const QString& appId, TaskController::Error error); |
207 | void onFocusRequested(const QString& appId); |
208 | - void onResumeRequested(const QString& appId); |
209 | |
210 | Q_SIGNALS: |
211 | void emptyChanged(); |
212 | @@ -132,6 +131,7 @@ |
213 | QModelIndex findIndex(Application* application); |
214 | void resumeApplication(Application *application); |
215 | QString toString() const; |
216 | + void createNewApplication(const QString &appId); |
217 | |
218 | Application* findApplicationWithPromptSession(const mir::scene::PromptSession* promptSession); |
219 | Application *findClosingApplication(const QString &inputAppId) const; |
220 | |
221 | === modified file 'src/modules/Unity/Application/mirsurfacelistmodel.cpp' |
222 | --- src/modules/Unity/Application/mirsurfacelistmodel.cpp 2016-05-17 19:57:52 +0000 |
223 | +++ src/modules/Unity/Application/mirsurfacelistmodel.cpp 2016-06-16 20:19:32 +0000 |
224 | @@ -20,6 +20,9 @@ |
225 | |
226 | #include <paths.h> |
227 | |
228 | +#include <QDebug> |
229 | +#include <QDebugStateSaver> |
230 | + |
231 | namespace unityapp = unity::shell::application; |
232 | using namespace qtmir; |
233 | |
234 | @@ -284,3 +287,21 @@ |
235 | |
236 | return m_sourceList->data(index, role); |
237 | } |
238 | + |
239 | +QDebug operator<<(QDebug dbg, const unityapp::MirSurfaceListInterface &surfaceListConst) |
240 | +{ |
241 | + auto surfaceList = const_cast<unityapp::MirSurfaceListInterface*>(&surfaceListConst); |
242 | + |
243 | + QDebugStateSaver saver(dbg); |
244 | + dbg.nospace(); |
245 | + dbg << "MirSurfaceList("; |
246 | + for (int i = 0; i < surfaceList->count(); ++i) { |
247 | + if (i > 0) { |
248 | + dbg << ", "; |
249 | + } |
250 | + auto surface = surfaceList->get(i); |
251 | + dbg << (void*)surface; |
252 | + } |
253 | + dbg << ')'; |
254 | + return dbg; |
255 | +} |
256 | |
257 | === modified file 'src/modules/Unity/Application/mirsurfacelistmodel.h' |
258 | --- src/modules/Unity/Application/mirsurfacelistmodel.h 2016-05-10 21:06:21 +0000 |
259 | +++ src/modules/Unity/Application/mirsurfacelistmodel.h 2016-06-16 20:19:32 +0000 |
260 | @@ -94,4 +94,6 @@ |
261 | |
262 | } // namespace qtmir |
263 | |
264 | +QDebug operator<<(QDebug, const unity::shell::application::MirSurfaceListInterface &); |
265 | + |
266 | #endif // QTMIR_MIRSURFACELISTMODEL_H |
267 | |
268 | === modified file 'src/modules/Unity/Application/session.cpp' |
269 | --- src/modules/Unity/Application/session.cpp 2016-05-17 19:18:44 +0000 |
270 | +++ src/modules/Unity/Application/session.cpp 2016-06-16 20:19:32 +0000 |
271 | @@ -38,6 +38,8 @@ |
272 | |
273 | using unity::shell::application::ApplicationInfoInterface; |
274 | |
275 | +#define DEBUG_MSG qCDebug(QTMIR_SURFACES).nospace() << "Session[" << (void*)this << ",name=" << name() << "]::" << __func__ |
276 | + |
277 | namespace qtmir |
278 | { |
279 | |
280 | @@ -75,7 +77,7 @@ |
281 | , m_live(true) |
282 | , m_promptSessionManager(promptSessionManager) |
283 | { |
284 | - qCDebug(QTMIR_SESSIONS) << "Session::Session() " << this->name(); |
285 | + DEBUG_MSG << "()"; |
286 | |
287 | setSuspendTimer(new Timer); |
288 | |
289 | @@ -84,7 +86,7 @@ |
290 | |
291 | Session::~Session() |
292 | { |
293 | - qCDebug(QTMIR_SESSIONS) << "Session::~Session() " << name(); |
294 | + DEBUG_MSG << "()"; |
295 | stopPromptSessions(); |
296 | |
297 | QList<SessionInterface*> children(m_children->list()); |
298 | @@ -107,7 +109,7 @@ |
299 | Q_ASSERT(m_state == Session::Suspending); |
300 | |
301 | if (m_surfaceList.count() == 0) { |
302 | - qCDebug(QTMIR_SESSIONS) << "Application::suspend - no surface to call stopFrameDropper() on!"; |
303 | + DEBUG_MSG << " no surface to call stopFrameDropper() on!"; |
304 | } else { |
305 | for (int i = 0; i < m_surfaceList.count(); ++i) { |
306 | auto surface = static_cast<MirSurfaceInterface*>(m_surfaceList.get(i)); |
307 | @@ -153,8 +155,7 @@ |
308 | return; |
309 | } |
310 | |
311 | - qCDebug(QTMIR_SESSIONS) << "Session::setState - session=" << name() |
312 | - << "state=" << sessionStateToString(state); |
313 | + DEBUG_MSG << "(state=" << sessionStateToString(state) << ")"; |
314 | |
315 | if (m_state == Suspending) { |
316 | m_suspendTimer->stop(); |
317 | @@ -198,7 +199,7 @@ |
318 | |
319 | void Session::registerSurface(MirSurfaceInterface *newSurface) |
320 | { |
321 | - qCDebug(QTMIR_SESSIONS) << "Session::resgisterSurface - session=" << name() << "surface=" << newSurface; |
322 | + DEBUG_MSG << "(surface=" << newSurface << ")"; |
323 | |
324 | // Only notify QML of surface creation once it has drawn its first frame. |
325 | if (newSurface->isFirstFrameDrawn()) { |
326 | @@ -214,7 +215,7 @@ |
327 | |
328 | void Session::prependSurface(MirSurfaceInterface *newSurface) |
329 | { |
330 | - qCDebug(QTMIR_SESSIONS) << "Session::prependSurface - session=" << name() << "surface=" << newSurface; |
331 | + DEBUG_MSG << "(surface=" << newSurface << ")"; |
332 | |
333 | connect(newSurface, &MirSurfaceInterface::stateChanged, |
334 | this, &Session::updateFullscreenProperty); |
335 | @@ -246,7 +247,7 @@ |
336 | |
337 | void Session::removeSurface(MirSurfaceInterface* surface) |
338 | { |
339 | - qCDebug(QTMIR_SESSIONS) << "Session::removeSurface - session=" << name() << "surface=" << surface; |
340 | + DEBUG_MSG << "(surface=" << surface << ")"; |
341 | |
342 | surface->disconnect(this); |
343 | |
344 | @@ -277,8 +278,8 @@ |
345 | |
346 | void Session::setFullscreen(bool fullscreen) |
347 | { |
348 | - qCDebug(QTMIR_SESSIONS) << "Session::setFullscreen - session=" << this << "fullscreen=" << fullscreen; |
349 | if (m_fullscreen != fullscreen) { |
350 | + DEBUG_MSG << "(" << fullscreen << ")"; |
351 | m_fullscreen = fullscreen; |
352 | Q_EMIT fullscreenChanged(m_fullscreen); |
353 | } |
354 | @@ -286,7 +287,7 @@ |
355 | |
356 | void Session::suspend() |
357 | { |
358 | - qCDebug(QTMIR_SESSIONS) << "Session::suspend - session=" << this << "state=" << sessionStateToString(m_state); |
359 | + DEBUG_MSG << " state=" << sessionStateToString(m_state); |
360 | if (m_state == Running) { |
361 | session()->set_lifecycle_state(mir_lifecycle_state_will_suspend); |
362 | m_suspendTimer->start(); |
363 | @@ -305,7 +306,7 @@ |
364 | |
365 | void Session::resume() |
366 | { |
367 | - qCDebug(QTMIR_SESSIONS) << "Session::resume - session=" << this << "state=" << sessionStateToString(m_state); |
368 | + DEBUG_MSG << " state=" << sessionStateToString(m_state); |
369 | |
370 | if (m_state == Suspending || m_state == Suspended) { |
371 | doResume(); |
372 | @@ -336,7 +337,7 @@ |
373 | |
374 | void Session::close() |
375 | { |
376 | - qCDebug(QTMIR_SESSIONS) << "Session::close - " << name(); |
377 | + DEBUG_MSG << "()"; |
378 | |
379 | if (m_state == Stopped) return; |
380 | |
381 | @@ -348,7 +349,7 @@ |
382 | |
383 | void Session::stop() |
384 | { |
385 | - qCDebug(QTMIR_SESSIONS) << "Session::stop - " << name(); |
386 | + DEBUG_MSG << "()"; |
387 | |
388 | if (m_state != Stopped) { |
389 | |
390 | @@ -372,7 +373,7 @@ |
391 | void Session::setLive(const bool live) |
392 | { |
393 | if (m_live != live) { |
394 | - qCDebug(QTMIR_SESSIONS) << "Session::setLive - " << name() << "live=" << live; |
395 | + DEBUG_MSG << "(" << live << ")"; |
396 | |
397 | m_live = live; |
398 | Q_EMIT liveChanged(m_live); |
399 | @@ -396,7 +397,7 @@ |
400 | |
401 | void Session::insertChildSession(uint index, SessionInterface* session) |
402 | { |
403 | - qCDebug(QTMIR_SESSIONS) << "Session::insertChildSession - " << session->name() << " to " << name() << " @ " << index; |
404 | + DEBUG_MSG << "(index=" << index << ", Session[" << (void*)session << ",name=" << session->name() << "])"; |
405 | Q_ASSERT(!m_children->contains(session)); |
406 | |
407 | m_children->insert(index, session); |
408 | @@ -424,7 +425,7 @@ |
409 | |
410 | void Session::removeChildSession(SessionInterface* session) |
411 | { |
412 | - qCDebug(QTMIR_SESSIONS) << "Session::removeChildSession - " << session->name() << " from " << name(); |
413 | + DEBUG_MSG << "(Session[" << (void*)session << ",name=" << session->name() << "])"; |
414 | |
415 | disconnect(session, 0, this, 0); |
416 | |
417 | @@ -452,16 +453,14 @@ |
418 | |
419 | void Session::appendPromptSession(const std::shared_ptr<ms::PromptSession>& promptSession) |
420 | { |
421 | - qCDebug(QTMIR_SESSIONS) << "Session::appendPromptSession session=" << name() |
422 | - << "promptSession=" << (promptSession ? promptSession.get() : nullptr); |
423 | + DEBUG_MSG << "(promptSession=" << (promptSession ? promptSession.get() : nullptr) << ")"; |
424 | |
425 | m_promptSessions.append(promptSession); |
426 | } |
427 | |
428 | void Session::removePromptSession(const std::shared_ptr<ms::PromptSession>& promptSession) |
429 | { |
430 | - qCDebug(QTMIR_SESSIONS) << "Session::removePromptSession session=" << name() |
431 | - << "promptSession=" << (promptSession ? promptSession.get() : nullptr); |
432 | + DEBUG_MSG << "(promptSession=" << (promptSession ? promptSession.get() : nullptr) << ")"; |
433 | |
434 | m_promptSessions.removeAll(promptSession); |
435 | } |
436 | @@ -477,7 +476,7 @@ |
437 | QListIterator<std::shared_ptr<ms::PromptSession>> it(copy); |
438 | for ( it.toBack(); it.hasPrevious(); ) { |
439 | std::shared_ptr<ms::PromptSession> promptSession = it.previous(); |
440 | - qCDebug(QTMIR_SESSIONS) << "Session::stopPromptSessions - promptSession=" << promptSession.get(); |
441 | + DEBUG_MSG << " - promptSession=" << promptSession.get(); |
442 | |
443 | m_promptSessionManager->stop_prompt_session(promptSession); |
444 | } |
445 | @@ -500,7 +499,7 @@ |
446 | void Session::deleteIfZombieAndEmpty() |
447 | { |
448 | if (!m_live && m_children->rowCount() == 0 && m_surfaceList.isEmpty()) { |
449 | - qCDebug(QTMIR_SESSIONS).nospace() << "Session::deleteIfZombieAndEmpty[" << name() << "] - deleteLater()"; |
450 | + DEBUG_MSG << " - deleteLater()"; |
451 | deleteLater(); |
452 | } |
453 | } |
454 | |
455 | === modified file 'src/modules/Unity/Application/taskcontroller.h' |
456 | --- src/modules/Unity/Application/taskcontroller.h 2016-04-22 14:03:26 +0000 |
457 | +++ src/modules/Unity/Application/taskcontroller.h 2016-06-16 20:19:32 +0000 |
458 | @@ -1,5 +1,5 @@ |
459 | /* |
460 | - * Copyright (C) 2014-2015 Canonical, Ltd. |
461 | + * Copyright (C) 2014-2016 Canonical, Ltd. |
462 | * |
463 | * This program is free software: you can redistribute it and/or modify it under |
464 | * the terms of the GNU Lesser General Public License version 3, as published by |
465 | @@ -54,6 +54,10 @@ |
466 | |
467 | virtual QSharedPointer<qtmir::ApplicationInfo> getInfoForApp(const QString &appId) const = 0; |
468 | |
469 | + // Not a perfect fit for this class but we need the kill(pid_t pid, int sig) function |
470 | + // behind an interface so we can test it (replacing with a mock or fake) |
471 | + virtual void kill(pid_t pid) = 0; |
472 | + |
473 | Q_SIGNALS: |
474 | void processStarting(const QString &appId); |
475 | void applicationStarted(const QString &appId); |
476 | |
477 | === modified file 'src/modules/Unity/Application/upstart/taskcontroller.cpp' |
478 | --- src/modules/Unity/Application/upstart/taskcontroller.cpp 2016-05-04 16:35:50 +0000 |
479 | +++ src/modules/Unity/Application/upstart/taskcontroller.cpp 2016-06-16 20:19:32 +0000 |
480 | @@ -30,6 +30,9 @@ |
481 | } |
482 | #include <ubuntu-app-launch/registry.h> |
483 | |
484 | +// std |
485 | +#include <csignal> |
486 | + |
487 | namespace ual = ubuntu::app_launch; |
488 | |
489 | namespace qtmir |
490 | @@ -243,5 +246,10 @@ |
491 | return QSharedPointer<qtmir::ApplicationInfo>(appInfo); |
492 | } |
493 | |
494 | +void TaskController::kill(pid_t pid) |
495 | +{ |
496 | + ::kill(pid, SIGTERM); |
497 | +} |
498 | + |
499 | } // namespace upstart |
500 | } // namespace qtmir |
501 | |
502 | === modified file 'src/modules/Unity/Application/upstart/taskcontroller.h' |
503 | --- src/modules/Unity/Application/upstart/taskcontroller.h 2016-04-22 14:03:26 +0000 |
504 | +++ src/modules/Unity/Application/upstart/taskcontroller.h 2016-06-16 20:19:32 +0000 |
505 | @@ -41,6 +41,8 @@ |
506 | |
507 | QSharedPointer<qtmir::ApplicationInfo> getInfoForApp(const QString &appId) const override; |
508 | |
509 | + void kill(pid_t pid) override; |
510 | + |
511 | private: |
512 | struct Private; |
513 | QScopedPointer<Private> impl; |
514 | |
515 | === modified file 'tests/framework/mock_task_controller.h' |
516 | --- tests/framework/mock_task_controller.h 2016-04-22 14:03:26 +0000 |
517 | +++ tests/framework/mock_task_controller.h 2016-06-16 20:19:32 +0000 |
518 | @@ -38,6 +38,7 @@ |
519 | MOCK_METHOD2(start, bool(const QString&, const QStringList&)); |
520 | MOCK_METHOD1(suspend, bool(const QString&)); |
521 | MOCK_METHOD1(resume, bool(const QString&)); |
522 | + MOCK_METHOD1(kill, void(pid_t pid)); |
523 | |
524 | bool doAppIdHasProcessId(const QString& appId, pid_t pid); |
525 | |
526 | |
527 | === modified file 'tests/modules/ApplicationManager/application_manager_test.cpp' |
528 | --- tests/modules/ApplicationManager/application_manager_test.cpp 2016-05-03 15:27:26 +0000 |
529 | +++ tests/modules/ApplicationManager/application_manager_test.cpp 2016-06-16 20:19:32 +0000 |
530 | @@ -1900,3 +1900,176 @@ |
531 | |
532 | EXPECT_EQ(1, focusRequestedSpy.count()); |
533 | } |
534 | + |
535 | +/* |
536 | + * Context: |
537 | + * - we are waiting for an application to quit following a close() |
538 | + * |
539 | + * Event: |
540 | + * - TaskController requests that application to be resumed. |
541 | + * Most likely because the user tapped the app icon in the Dash. From the user's |
542 | + * perspective the application is already closed and he wants to start a new |
543 | + * instance of it. |
544 | + * But from TaskController's perspective the application is still running and |
545 | + * therefore should just be resumed/focused. |
546 | + * |
547 | + * Expected outcome: |
548 | + * - ApplicationManager should wait for the closing application to finally end (or |
549 | + be killed) and then finally launch a new instance of it. |
550 | + * |
551 | + * Regression test for https://bugs.launchpad.net/ubuntu/+source/qtmir/+bug/1527737 |
552 | + * "Apps do not start if restarted quickly after closing" |
553 | + * |
554 | + * Two test versions: |
555 | + * _appQuits - Application complies and quits |
556 | + * _appKilled - Application ignores close request and thus get killed |
557 | + */ |
558 | +TEST_F(ApplicationManagerTests, focusRequestedForClosingApplication_appQuits) |
559 | +{ |
560 | + using namespace ::testing; |
561 | + |
562 | + int argc = 0; |
563 | + char* argv[0]; |
564 | + QCoreApplication qtApp(argc, argv); // app for deleteLater event |
565 | + |
566 | + const QString appId("testAppId"); |
567 | + quint64 procId = 5551; |
568 | + |
569 | + ON_CALL(*taskController, appIdHasProcessId(appId, procId)).WillByDefault(Return(true)); |
570 | + |
571 | + EXPECT_CALL(*taskController, start(appId, _)) |
572 | + .Times(1) |
573 | + .WillOnce(Return(true)); |
574 | + |
575 | + auto app = applicationManager.startApplication(appId); |
576 | + applicationManager.onProcessStarting(appId); |
577 | + std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
578 | + bool authed = true; |
579 | + applicationManager.authorizeSession(procId, authed); |
580 | + ASSERT_TRUE(authed); |
581 | + onSessionStarting(session); |
582 | + |
583 | + FakeMirSurface *surface = new FakeMirSurface; |
584 | + onSessionCreatedSurface(session.get(), surface); |
585 | + surface->drawFirstFrame(); |
586 | + |
587 | + ASSERT_EQ(Application::InternalState::Running, app->internalState()); |
588 | + |
589 | + QSignalSpy closeRequestedSpy(surface, SIGNAL(closeRequested())); |
590 | + |
591 | + // User swipes away the application, visually closing/removing it. |
592 | + applicationManager.stopApplication(appId); |
593 | + |
594 | + // But asking ApplicationManager to stop the application just makes it request its |
595 | + // surfaces to be closed |
596 | + EXPECT_EQ(Application::InternalState::Closing, app->internalState()); |
597 | + EXPECT_EQ(1, closeRequestedSpy.count()); |
598 | + |
599 | + // User then taps on the app icon |
600 | + applicationManager.onProcessStarting(appId); |
601 | + applicationManager.onFocusRequested(appId); |
602 | + |
603 | + // But no application instance should have been created because of that |
604 | + EXPECT_TRUE(applicationManager.findApplication(appId) == nullptr); |
605 | + |
606 | + // ApplicationManager will ask TaskController to start the application again |
607 | + // once the closing instance is gone |
608 | + Mock::VerifyAndClearExpectations(taskController); |
609 | + EXPECT_CALL(*taskController, start(appId, _)) |
610 | + .Times(1) |
611 | + .WillOnce(Return(true)); |
612 | + |
613 | + // Simulates that the application complied to the close() request and stopped itself |
614 | + onSessionStopping(session); |
615 | + applicationManager.onProcessStopped(appId); |
616 | + |
617 | + // DeferredDelete is special: likes to be called out specifically or it won't come out |
618 | + qtApp.sendPostedEvents(app, QEvent::DeferredDelete); |
619 | + qtApp.sendPostedEvents(); |
620 | + |
621 | + EXPECT_TRUE(applicationManager.findApplication(appId) != nullptr); |
622 | +} |
623 | +TEST_F(ApplicationManagerTests, focusRequestedForClosingApplication_appKilled) |
624 | +{ |
625 | + using namespace ::testing; |
626 | + |
627 | + int argc = 0; |
628 | + char* argv[0]; |
629 | + QCoreApplication qtApp(argc, argv); // app for deleteLater event |
630 | + |
631 | + const QString appId("testAppId"); |
632 | + quint64 procId = 5551; |
633 | + |
634 | + ON_CALL(*taskController, appIdHasProcessId(appId, procId)).WillByDefault(Return(true)); |
635 | + |
636 | + EXPECT_CALL(*taskController, start(appId, _)) |
637 | + .Times(1) |
638 | + .WillOnce(Return(true)); |
639 | + |
640 | + auto app = applicationManager.startApplication(appId); |
641 | + applicationManager.onProcessStarting(appId); |
642 | + std::shared_ptr<mir::scene::Session> session = std::make_shared<MockSession>("", procId); |
643 | + bool authed = true; |
644 | + applicationManager.authorizeSession(procId, authed); |
645 | + ASSERT_TRUE(authed); |
646 | + onSessionStarting(session); |
647 | + |
648 | + FakeMirSurface *surface = new FakeMirSurface; |
649 | + onSessionCreatedSurface(session.get(), surface); |
650 | + surface->drawFirstFrame(); |
651 | + |
652 | + EXPECT_EQ(Application::InternalState::Running, app->internalState()); |
653 | + |
654 | + QSharedPointer<FakeTimeSource> fakeTimeSource(new FakeTimeSource); |
655 | + FakeTimer *fakeStopTimer = new FakeTimer(fakeTimeSource); |
656 | + app->setStopTimer(fakeStopTimer); |
657 | + |
658 | + QSignalSpy closeRequestedSpy(surface, SIGNAL(closeRequested())); |
659 | + |
660 | + // User swipes away the application, visually closing/removing it. |
661 | + applicationManager.stopApplication(appId); |
662 | + |
663 | + // But asking ApplicationManager to stop the application just makes it request its |
664 | + // surfaces to be closed |
665 | + EXPECT_EQ(Application::InternalState::Closing, app->internalState()); |
666 | + EXPECT_EQ(1, closeRequestedSpy.count()); |
667 | + |
668 | + // User then taps on the app icon |
669 | + applicationManager.onProcessStarting(appId); |
670 | + applicationManager.onFocusRequested(appId); |
671 | + |
672 | + // But no application instance should have been created because of that |
673 | + EXPECT_TRUE(applicationManager.findApplication(appId) == nullptr); |
674 | + |
675 | + // ApplicationManager will ask TaskController to start the application again |
676 | + // once the closing instance is gone |
677 | + Mock::VerifyAndClearExpectations(taskController); |
678 | + EXPECT_CALL(*taskController, start(appId, _)) |
679 | + .Times(1) |
680 | + .WillOnce(Return(true)); |
681 | + |
682 | + EXPECT_CALL(*taskController, stop(appId)) |
683 | + .Times(1) |
684 | + .WillOnce(Return(false)); |
685 | + |
686 | + EXPECT_CALL(*taskController, kill(procId)) |
687 | + .Times(1) |
688 | + .WillOnce(Invoke( |
689 | + [this, session](pid_t) { |
690 | + // simulate application dying and thus severing the mir connection |
691 | + onSessionStopping(session); |
692 | + } |
693 | + )); |
694 | + |
695 | + if (fakeStopTimer->isRunning()) { |
696 | + // Simulate that it has timed out. |
697 | + fakeTimeSource->m_msecsSinceReference = fakeStopTimer->nextTimeoutTime() + 1; |
698 | + fakeStopTimer->update(); |
699 | + } |
700 | + |
701 | + // DeferredDelete is special: likes to be called out specifically or it won't come out |
702 | + qtApp.sendPostedEvents(app, QEvent::DeferredDelete); |
703 | + qtApp.sendPostedEvents(); |
704 | + |
705 | + EXPECT_TRUE(applicationManager.findApplication(appId) != nullptr); |
706 | +} |
FAILED: Continuous integration, rev:436 jenkins. qa.ubuntu. com/job/ qtmir-ci/ 628/ jenkins. qa.ubuntu. com/job/ qtmir-vivid- amd64-ci/ 322 jenkins. qa.ubuntu. com/job/ qtmir-vivid- armhf-ci/ 324 jenkins. qa.ubuntu. com/job/ qtmir-vivid- armhf-ci/ 324/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ qtmir-vivid- i386-ci/ 204 jenkins. qa.ubuntu. com/job/ qtmir-wily- amd64-ci/ 359/console jenkins. qa.ubuntu. com/job/ qtmir-wily- armhf-ci/ 361/console jenkins. qa.ubuntu. com/job/ qtmir-wily- i386-ci/ 204/console
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/qtmir- ci/628/ rebuild
http://