Merge lp:~thomas-voss/unity-mir/refactor-oom-score-adj-to-rely-on-process-cpp into lp:unity-mir

Proposed by Thomas Voß
Status: Superseded
Proposed branch: lp:~thomas-voss/unity-mir/refactor-oom-score-adj-to-rely-on-process-cpp
Merge into: lp:unity-mir
Diff against target: 1737 lines (+989/-488)
26 files modified
CMakeLists.txt (+64/-0)
data/CMakeLists.txt (+7/-0)
data/unity-mir.pc.in (+10/-0)
debian/control (+3/-0)
debian/rules (+0/-3)
src/CMakeLists.txt (+2/-0)
src/modules/CMakeLists.txt (+1/-0)
src/modules/Unity/Application/Application.pro (+0/-58)
src/modules/Unity/Application/CMakeLists.txt (+97/-0)
src/modules/Unity/Application/application.cpp (+1/-0)
src/modules/Unity/Application/application.h (+0/-3)
src/modules/Unity/Application/application_controller.h (+61/-0)
src/modules/Unity/Application/dbuswindowstack.h (+2/-2)
src/modules/Unity/Application/taskcontroller.cpp (+178/-334)
src/modules/Unity/Application/taskcontroller.h (+31/-10)
src/modules/Unity/Application/upstart/application_controller.cpp (+154/-0)
src/modules/Unity/Application/upstart/application_controller.h (+44/-0)
src/modules/Unity/CMakeLists.txt (+1/-0)
src/modules/modules.pro (+0/-3)
src/src.pro (+0/-6)
src/unity-mir/CMakeLists.txt (+72/-0)
src/unity-mir/logging.h (+2/-0)
src/unity-mir/unity-mir.pro (+0/-67)
tests/CMakeLists.txt (+48/-0)
tests/taskcontroller_test.cpp (+211/-0)
unity-mir.pro (+0/-2)
To merge this branch: bzr merge lp:~thomas-voss/unity-mir/refactor-oom-score-adj-to-rely-on-process-cpp
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) Needs Fixing
PS Jenkins bot (community) continuous-integration Approve
Michał Sawicz Needs Fixing
Review via email: mp+194797@code.launchpad.net

This proposal has been superseded by a proposal from 2014-01-10.

Commit message

Refactor Oom(Score)Adj to rely on process-cpp helper library.

Description of the change

Refactor Oom(Score)Adj to rely on process-cpp helper library.

To post a comment you must log in.
Revision history for this message
Michał Sawicz (saviq) wrote :

Missing debian/control entry.

review: Needs Fixing
144. By Thomas Voß

Add build-dependency on libprocess-cpp.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
145. By Thomas Voß

Refactor to core namespace.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
146. By Thomas Voß

[ Gerry Boland ]
* Unity.Application is not a shared library, but a plugin. (LP:
  #1256014)
* Implement preStart callback added to upstart-app-launch-2. (LP:
  #1243665)
[ Ubuntu daily release ]
* Automatic snapshot from revision 157
[ Gerry Boland ]
* Install ServerStatusListener to be notified of mir server start, pause
  and resume. Use start notification to send SIGSTOP signal to upstart,
  so it knows mir is ready for other clients.
* Bump version number
* InputArea: don't use lambda function as slot, can cause crash on
  shutdown Using lambda function as slot can introduce crash as the
  slot's object deletion is not registered unlike with traditional
  signal/slot connections. As a result, on signal emission, the lambda
  can be called on a deleted object. (LP: #1253685)
* Misc fixes for Mir 0.1.2 support. (LP: #1254986)
[ Alan Griffiths ]
* ApplicationSession is a Mir implementation class that shouldn't be
  used by unity-mir, use shell::session instead.
[ Kevin Gunn ]
* mir server abi and api broke, updating dependency to deb 0.1.1.
* update mir deb build dep to 0.1.2
[ Victor Thompson ]
* Fix mir to not suspend the music-app, or any other app granted a
  lifecycle exception, when switching between apps. (LP: #1241185,
  #1241045)
[ Daniel van Vugt ]
* Force the screen to redraw after turning the display back on (LP:
  #1255045). Also stop the compositor when the screen is off.
  Otherwise it will spin in the background, eating battery. (LP:
  #1255045)
[ Ubuntu daily release ]
* Automatic snapshot from revision 154
* Cherry-pick upstream patch to avoid Unity8 crashing on stop
  (LP: #1253685)
[ Gerry Boland ]
* On MirSurface destruction, any InputAreas on that surface will be
  notified and remove their links to that surface. Fixes crash
  bug:1243444. (LP: #1243444)
[ Alan Griffiths ]
* Remove dependency on mir::shell::SessionManager.
* Remove dependency on mir::surfaces::SurfaceController.
* Remove dependency on msh::OrganisingSurfaceFactory.
* Avoid relying on an explicit Mir typename that changes in a
  refactoring coming soon.
* Do all the hacky surface creation customization in
  SurfaceFactory::create_surface() - and don't mention SurfaceBuilder
  at all. (That will allow Mir to get rid of that interface.).
[ Albert Astals ]
* Don't include the QtQml megaheader Include the one we really need.
[ Ubuntu daily release ]
* Automatic snapshot from revision 144

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

There's an indentation issue in debian/control (please use spaces).

Why do we fall back to the deprecated method? Are there any cases where we expect process cpp to raise that is an "expected failure"?

"extremal" is not a word?

Should we maybe store shellScore instead of reading it off of the shell process every time?

This would be a good time to auto-test this, would it not?

review: Needs Fixing
147. By Thomas Voß

Fix whitespace.

148. By Thomas Voß

Replace extremal with boundary.

Revision history for this message
Thomas Voß (thomas-voss) wrote :

> There's an indentation issue in debian/control (please use spaces).
>

Fixed.

> Why do we fall back to the deprecated method? Are there any cases where we
> expect process cpp to raise that is an "expected failure"?
>

While the method is deprecated it is still present and common in the Android world.
Process-cpp just raises an exception if it is unable to adjust the score, i.e., unable to write to the respective file. I think the fallback renders the overall implementation more robust in real-world scenarios.

> "extremal" is not a word?
>

Fixed.

> Should we maybe store shellScore instead of reading it off of the shell
> process every time?
>

We need to read it everytime as the score might have been adjusted by the kernel in the meantime.

> This would be a good time to auto-test this, would it not?

True, will take care of that task.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
149. By Thomas Voß

Merge cmake setup.
Add testing setup.

[ Daniel d'Andrada ]
* Fix OSKController.enabled property OSKController.enabled was always
  True as we were missing the check for undefined. Also s/variant/var
  as the "variant" QML type is deprecated. (LP: #1248795)
[ kevin gunn ]
* bump debian version dependency for mir to 0.1.3 to force rebuild
[ Ubuntu daily release ]
* Automatic snapshot from revision 160

150. By Thomas Voß

Add build-dependency on Google Mock.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

there's a src/modules/Unity/Application/Application.pro.THIS file taht probably has to go away.

review: Needs Fixing
151. By Thomas Voß

Remove leftover pro file.

152. By Thomas Voß

Merge pre-requisite branch again.
Remove stale .pro.THIS file.

Revision history for this message
Thomas Voß (thomas-voss) wrote :

> there's a src/modules/Unity/Application/Application.pro.THIS file taht
> probably has to go away.

Good catch, fixed.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
153. By Thomas Voß

Remove obsolete copyright notice in build system file.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
154. By Thomas Voß

Add missing call for finding process-cpp.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

Which this i am getting libunity-mir.so.0.0.1 while with the master branch i get libunity-mir.so.1.0.0

I don't think this change is intentional, no?

review: Needs Fixing
155. By Thomas Voß

Merge prerequisite branch.

Revision history for this message
Thomas Voß (thomas-voss) wrote :

> Which this i am getting libunity-mir.so.0.0.1 while with the master branch i
> get libunity-mir.so.1.0.0
>
> I don't think this change is intentional, no?

Nope, it is not. Also fixed in prerequisite branch.

156. By Thomas Voß

Add a first test case for application manager.
Split up mocks into their own header file.

157. By Thomas Voß

Add test for focus setting behavior (disabled right now).

158. By Thomas Voß

Remove dead code.

159. By Thomas Voß

First wave of changes accounting for review.

160. By Thomas Voß

Refactor signal-slot connections in TaskController to type-safe variant.

161. By Thomas Voß

Refactor process operations into class ProcessController and an inner class ProcessController::OomController.

162. By Thomas Voß

[ Gerry Boland ]
* [cmake] set default build type to RelWithDebInfo, add workaround to
  set QT_NO_DEBUG with that option.
[ Albert Astals ]
* Tests for ApplicationManager start/stopApplication At the moment
  they just work on the device (well they may as well work on Mir on
  the desktop but have not tried). You need to install the libunity-
  mir-tests package and then run unity-mir-test-app.
[ Ricardo Mendoza ]
* Correctly respect lifecycle exceptions in the new sidestage model.
  (LP: #1269414)
[ Ubuntu daily release ]
* Automatic snapshot from revision 168
[ thomas-voss ]
* Switch to cmake.
[ Albert Astals ]
* Recover the Requires line in the .pc file.
[ Ricardo Mendoza ]
* Re-enable Sidestage as it was under SF.
[ Ubuntu daily release ]
* Automatic snapshot from revision 164

163. By Thomas Voß

Adjust slot signatures.

164. By Thomas Voß

Adjust copyright year.

165. By Thomas Voß

Replace auto variables with pid_t where appropriate.

166. By Thomas Voß

Switch to Q_EMIT for passing on signals originating from upstart app launch.

167. By Thomas Voß

Merged lp:~ricmm/unity-mir/catch-starting-failure.

168. By Thomas Voß

[ Kevin Gunn ]
* bump debian version for mir to 0.1.4
[ Łukasz 'sil2100' Zemczak ]
* Fix the multi-arch stanza in the new -tests package.

169. By Thomas Voß

Initialize ApplicationManager::m_focusedApplication to nullptr in ctor.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'CMakeLists.txt'
2--- CMakeLists.txt 1970-01-01 00:00:00 +0000
3+++ CMakeLists.txt 2014-01-10 09:14:26 +0000
4@@ -0,0 +1,64 @@
5+cmake_minimum_required(VERSION 2.8)
6+
7+project(Unity-Mir)
8+
9+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
10+
11+# Find includes in corresponding build directories
12+set(CMAKE_INCLUDE_CURRENT_DIR ON)
13+# Instruct CMake to run moc automatically when needed.
14+set(CMAKE_AUTOMOC ON)
15+
16+include(GNUInstallDirs)
17+
18+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -pedantic -Wextra")
19+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -fno-strict-aliasing -pedantic -Wextra")
20+set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
21+
22+option(Werror "Treat warnings as errors" ON)
23+if (Werror)
24+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror -Wno-error=format")
25+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wno-error=format")
26+endif()
27+
28+string(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type_lower)
29+
30+#####################################################################
31+# Enable code coverage calculation with gcov/gcovr/lcov
32+# Usage:
33+# * Switch build type to coverage (use ccmake or cmake-gui)
34+# * Invoke make, make test, make coverage
35+# * Find html report in subdir coveragereport
36+# * Find xml report feasible for jenkins in coverage.xml
37+#####################################################################
38+IF(cmake_build_type_lower MATCHES coverage)
39+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage -fprofile-arcs" )
40+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage -fprofile-arcs" )
41+ SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -ftest-coverage -fprofile-arcs" )
42+ SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -ftest-coverage -fprofile-arcs" )
43+ENDIF(cmake_build_type_lower MATCHES coverage)
44+
45+include(CTest)
46+
47+set(UNITY_MIR_VERSION_MAJOR 1)
48+set(UNITY_MIR_VERSION_MINOR 0)
49+set(UNITY_MIR_VERSION_PATCH 0)
50+
51+find_package(PkgConfig REQUIRED)
52+find_package(Threads REQUIRED)
53+
54+find_package(Qt5Core REQUIRED)
55+find_package(Qt5Quick REQUIRED)
56+find_package(Qt5DBus REQUIRED)
57+
58+pkg_check_modules(MIRSERVER mirserver REQUIRED)
59+pkg_check_modules(MIRCOMMON mircommon REQUIRED)
60+pkg_check_modules(UBUNTU_PLATFORM_API ubuntu-platform-api REQUIRED)
61+
62+add_subdirectory(src)
63+add_subdirectory(data)
64+
65+add_subdirectory(tests)
66+
67+# TODO(tvoss): Enable coverage reporting once we have tests in place.
68+#enable_coverage_report(posix_process_test linux_process_test)
69
70=== added directory 'data'
71=== added file 'data/CMakeLists.txt'
72--- data/CMakeLists.txt 1970-01-01 00:00:00 +0000
73+++ data/CMakeLists.txt 2014-01-10 09:14:26 +0000
74@@ -0,0 +1,7 @@
75+configure_file(
76+ ${CMAKE_CURRENT_SOURCE_DIR}/unity-mir.pc.in
77+ ${CMAKE_CURRENT_BINARY_DIR}/unity-mir.pc @ONLY)
78+
79+install(
80+ FILES ${CMAKE_CURRENT_BINARY_DIR}/unity-mir.pc
81+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
82
83=== added file 'data/unity-mir.pc.in'
84--- data/unity-mir.pc.in 1970-01-01 00:00:00 +0000
85+++ data/unity-mir.pc.in 2014-01-10 09:14:26 +0000
86@@ -0,0 +1,10 @@
87+prefix=@CMAKE_INSTALL_PREFIX@
88+exec_prefix=${prefix}
89+libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
90+includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
91+
92+Name: @CMAKE_PROJECT_NAME@
93+Description: Qt wrapper for Mir functionality required by Unity
94+Version: @UNITY_MIR_VERSION_MAJOR@.@UNITY_MIR_VERSION_MINOR@.@UNITY_MIR_VERSION_PATCH@
95+Libs: -L${libdir} -lunity-mir
96+Cflags: -I${includedir}/unity-mir
97
98=== modified file 'debian/control'
99--- debian/control 2014-01-02 21:27:18 +0000
100+++ debian/control 2014-01-10 09:14:26 +0000
101@@ -3,10 +3,13 @@
102 Priority: optional
103 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
104 Build-Depends: debhelper (>= 9),
105+ cmake,
106+ google-mock (>= 1.6.0+svn437),
107 pkg-config,
108 libplatform-api1-dev,
109 libmirserver-dev (>= 0.1.3),
110 libmirclient-dev (>= 0.1.3),
111+ libprocess-cpp-dev,
112 libunity-api-dev,
113 libupstart-app-launch2-dev,
114 qt5-default,
115
116=== modified file 'debian/rules'
117--- debian/rules 2013-08-19 07:40:07 +0000
118+++ debian/rules 2014-01-10 09:14:26 +0000
119@@ -6,6 +6,3 @@
120 %:
121 dh $@ --parallel --fail-missing
122
123-# Force the build to generate debug symbols, so we can have -dbgsym packages
124-override_dh_auto_configure:
125- dh_auto_configure -- QMAKE_CXXFLAGS=-g
126
127=== added file 'src/CMakeLists.txt'
128--- src/CMakeLists.txt 1970-01-01 00:00:00 +0000
129+++ src/CMakeLists.txt 2014-01-10 09:14:26 +0000
130@@ -0,0 +1,2 @@
131+add_subdirectory(unity-mir)
132+add_subdirectory(modules)
133
134=== added file 'src/modules/CMakeLists.txt'
135--- src/modules/CMakeLists.txt 1970-01-01 00:00:00 +0000
136+++ src/modules/CMakeLists.txt 2014-01-10 09:14:26 +0000
137@@ -0,0 +1,1 @@
138+add_subdirectory(Unity)
139
140=== removed file 'src/modules/Unity/Application/Application.pro'
141--- src/modules/Unity/Application/Application.pro 2013-12-06 12:30:14 +0000
142+++ src/modules/Unity/Application/Application.pro 1970-01-01 00:00:00 +0000
143@@ -1,58 +0,0 @@
144-TARGET = unityapplicationplugin
145-TEMPLATE = lib
146-
147-QT += core quick dbus
148-CONFIG += link_pkgconfig plugin
149-
150-# CONFIG += c++11 # only enables C++0x
151-QMAKE_CXXFLAGS = -std=c++11 -fvisibility=hidden -fvisibility-inlines-hidden
152-QMAKE_CXXFLAGS_RELEASE += -Werror # so no stop on warning in debug builds
153-QMAKE_LFLAGS = -std=c++11 -Wl,-no-undefined
154-
155-PKGCONFIG += mircommon mirserver ubuntu-platform-api glib-2.0 upstart-app-launch-2
156-
157-INCLUDEPATH += ../../../unity-mir
158-LIBS += -L../../../unity-mir -lunity-mir \
159- -lubuntu_application_api_mirserver #FIXME platform-api pkgconfig should set this
160-
161-TARGET = $$qtLibraryTarget($$TARGET)
162-uri = Unity.Application
163-
164-SOURCES += application_manager.cpp \
165- application.cpp \
166- desktopfilereader.cpp \
167- plugin.cpp \
168- applicationscreenshotprovider.cpp \
169- dbuswindowstack.cpp \
170- taskcontroller.cpp \
171- mirsurface.cpp \
172- mirsurfacemanager.cpp \
173- inputarea.cpp \
174- inputfilterarea.cpp \
175- shellinputarea.cpp \
176- ubuntukeyboardinfo.cpp
177-
178-HEADERS += application_manager.h \
179- application.h \
180- desktopfilereader.h \
181- applicationscreenshotprovider.h \
182- dbuswindowstack.h \
183- taskcontroller.h \
184- mirsurface.h \
185- mirsurfacemanager.h \
186- shellinputarea.h \
187- inputarea.h \
188- inputfilterarea.h \
189- ubuntukeyboardinfo.h \
190- /usr/include/unity/shell/application/ApplicationManagerInterface.h \
191- /usr/include/unity/shell/application/ApplicationInfoInterface.h
192-
193-installPath = $$[QT_INSTALL_IMPORTS]/Unity-Mir/$$replace(uri, \\., /)
194-
195-QML_FILES = qmldir ApplicationImage.qml OSKController.qml
196-qml_files.path = $$installPath
197-qml_files.files = $$QML_FILES
198-
199-target.path = $$installPath
200-
201-INSTALLS += target qml_files
202
203=== added file 'src/modules/Unity/Application/CMakeLists.txt'
204--- src/modules/Unity/Application/CMakeLists.txt 1970-01-01 00:00:00 +0000
205+++ src/modules/Unity/Application/CMakeLists.txt 2014-01-10 09:14:26 +0000
206@@ -0,0 +1,97 @@
207+pkg_check_modules(GLIB glib-2.0 REQUIRED)
208+pkg_check_modules(PROCESS_CPP process-cpp REQUIRED)
209+pkg_check_modules(UPSTART_APP_LAUNCH upstart-app-launch-2 REQUIRED)
210+
211+add_definitions(-DQT_PLUGIN)
212+
213+include_directories(
214+ ${GLIB_INCLUDE_DIRS}
215+ ${MIRCOMMON_INCLUDE_DIRS}
216+ ${MIRSERVER_INCLUDE_DIRS}
217+ ${PROCESS_CPP_INCLUDE_DIRS}
218+ ${UBUNTU_PLATFORM_API_INCLUDE_DIRS}
219+ ${UPSTART_APP_LAUNCH_INCLUDE_DIRS}
220+
221+ ${CMAKE_SOURCE_DIR}/src/unity-mir
222+)
223+
224+add_library(
225+ unityapplicationplugin SHARED
226+
227+ application_manager.cpp
228+ application.cpp
229+ desktopfilereader.cpp
230+ plugin.cpp
231+ applicationscreenshotprovider.cpp
232+ dbuswindowstack.cpp
233+ taskcontroller.cpp
234+ mirsurface.cpp
235+ mirsurfacemanager.cpp
236+ inputarea.cpp
237+ inputfilterarea.cpp
238+ shellinputarea.cpp
239+ ubuntukeyboardinfo.cpp
240+
241+ upstart/application_controller.h
242+ upstart/application_controller.cpp
243+
244+ application_controller.h
245+ application_manager.h
246+ application.h
247+ desktopfilereader.h
248+ applicationscreenshotprovider.h
249+ dbuswindowstack.h
250+ taskcontroller.h
251+ mirsurface.h
252+ mirsurfacemanager.h
253+ shellinputarea.h
254+ inputarea.h
255+ inputfilterarea.h
256+ ubuntukeyboardinfo.h
257+
258+ # We need to pull in some external header files
259+ /usr/include/unity/shell/application/ApplicationManagerInterface.h
260+ /usr/include/unity/shell/application/ApplicationInfoInterface.h
261+)
262+
263+# We should not need this line according to the Qt5/CMake docs.
264+# However, when removing it, include paths are not set and linking to Qt5 fails.
265+qt5_use_modules(unityapplicationplugin Core Quick DBus)
266+
267+target_link_libraries(
268+ unityapplicationplugin
269+
270+ unity-mir
271+
272+ ubuntu_application_api_mirserver
273+
274+ Qt5::Core
275+ Qt5::Quick
276+ Qt5::DBus
277+
278+ ${CMAKE_THREAD_LIBS_INIT}
279+
280+ ${GLIB_LDFLAGS}
281+ ${UBUNTU_PLATFORM_API_LIBRARIES}
282+ ${MIRCOMMON_LIBRARIES}
283+ ${MIRSERVER_LIBRARIES}
284+ ${PROCESS_CPP_LIBRARIES}
285+ ${UBUNTU_PLATFORM_API_LIBRARIES}
286+ ${UPSTART_APP_LAUNCH_LIBRARIES}
287+
288+ ubuntu_application_api_mirserver
289+)
290+
291+# Ideally, we would read the plugin installation location from cmake
292+# but this does not work currently.
293+set(PLUGIN_INSTALL_LOCATION "${CMAKE_INSTALL_LIBDIR}/qt5/imports/Unity-Mir/Unity/Application")
294+
295+message(STATUS "Installing Qt5 Unity-Application plugin to: ${PLUGIN_INSTALL_LOCATION}")
296+
297+install(
298+ TARGETS unityapplicationplugin
299+ LIBRARY DESTINATION ${PLUGIN_INSTALL_LOCATION})
300+
301+install(
302+ FILES qmldir ApplicationImage.qml OSKController.qml
303+ DESTINATION ${PLUGIN_INSTALL_LOCATION})
304
305=== modified file 'src/modules/Unity/Application/application.cpp'
306--- src/modules/Unity/Application/application.cpp 2013-11-15 17:53:17 +0000
307+++ src/modules/Unity/Application/application.cpp 2014-01-10 09:14:26 +0000
308@@ -25,6 +25,7 @@
309
310 // mir
311 #include <mir/shell/session.h>
312+#include <mir/shell/snapshot.h>
313
314 Application::Application(const QString &appId, Application::State state,
315 const QStringList &arguments, QObject *parent)
316
317=== modified file 'src/modules/Unity/Application/application.h'
318--- src/modules/Unity/Application/application.h 2013-10-28 15:39:00 +0000
319+++ src/modules/Unity/Application/application.h 2014-01-10 09:14:26 +0000
320@@ -20,9 +20,6 @@
321 // std
322 #include <memory>
323
324-// Mir
325-#include <mir/shell/snapshot.h>
326-
327 //Qt
328 #include <QtCore/QtCore>
329 #include <QImage>
330
331=== added file 'src/modules/Unity/Application/application_controller.h'
332--- src/modules/Unity/Application/application_controller.h 1970-01-01 00:00:00 +0000
333+++ src/modules/Unity/Application/application_controller.h 2014-01-10 09:14:26 +0000
334@@ -0,0 +1,61 @@
335+/*
336+ * Copyright (C) 2013 Canonical, Ltd.
337+ *
338+ * This program is free software: you can redistribute it and/or modify it under
339+ * the terms of the GNU Lesser General Public License version 3, as published by
340+ * the Free Software Foundation.
341+ *
342+ * This program is distributed in the hope that it will be useful, but WITHOUT
343+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
344+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
345+ * Lesser General Public License for more details.
346+ *
347+ * You should have received a copy of the GNU Lesser General Public License
348+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
349+ *
350+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
351+ */
352+
353+#ifndef APPLICATION_CONTROLLER_H
354+#define APPLICATION_CONTROLLER_H
355+
356+#include <QObject>
357+#include <QString>
358+#include <QStringList>
359+
360+class ApplicationController : public QObject
361+{
362+ Q_OBJECT
363+
364+public:
365+ enum class Error
366+ {
367+ APPLICATION_CRASHED,
368+ APPLICATION_FAILED_TO_START
369+ };
370+
371+ ApplicationController(const ApplicationController&) = delete;
372+ virtual ~ApplicationController() = default;
373+
374+ ApplicationController& operator=(const ApplicationController&) = delete;
375+
376+ virtual pid_t primaryPidForAppId(const QString& appId) = 0;
377+ virtual bool appIdHasProcessId(pid_t pid, const QString& appId) = 0;
378+
379+ virtual bool stopApplicationWithAppId(const QString& appId) = 0;
380+ virtual bool startApplicationWithAppIdAndArgs(const QString& appId, const QStringList& arguments) = 0;
381+
382+Q_SIGNALS:
383+ void applicationAboutToBeStarted(QString id);
384+ void applicationStarted(QString id);
385+ void applicationStopped(QString id);
386+ void applicationFocusRequest(QString id);
387+ void applicationResumeRequest(QString id);
388+
389+ void applicationError(QString id, ApplicationController::Error error);
390+
391+protected:
392+ ApplicationController() = default;
393+};
394+
395+#endif // APPLICATION_CONTROLLER_H
396
397=== modified file 'src/modules/Unity/Application/dbuswindowstack.h'
398--- src/modules/Unity/Application/dbuswindowstack.h 2013-10-09 09:02:23 +0000
399+++ src/modules/Unity/Application/dbuswindowstack.h 2014-01-10 09:14:26 +0000
400@@ -62,7 +62,7 @@
401 void WindowDestroyed(unsigned int window_id, const QString &app_id);
402 };
403
404-Q_DECLARE_METATYPE(AppIdDesktopFile);
405-Q_DECLARE_METATYPE(WindowInfo);
406+Q_DECLARE_METATYPE(AppIdDesktopFile)
407+Q_DECLARE_METATYPE(WindowInfo)
408
409 #endif // DBUSWINDOWSTACK_H
410
411=== modified file 'src/modules/Unity/Application/taskcontroller.cpp'
412--- src/modules/Unity/Application/taskcontroller.cpp 2013-12-05 17:30:57 +0000
413+++ src/modules/Unity/Application/taskcontroller.cpp 2014-01-10 09:14:26 +0000
414@@ -18,6 +18,7 @@
415
416 // local
417 #include "taskcontroller.h"
418+#include "upstart/application_controller.h"
419
420 // unity-mir
421 #include <logging.h>
422@@ -25,6 +26,12 @@
423 // Qt
424 #include <QStringList>
425
426+// Process C++
427+#include <core/posix/process.h>
428+#include <core/posix/this_process.h>
429+#include <core/posix/linux/proc/process/oom_adj.h>
430+#include <core/posix/linux/proc/process/oom_score_adj.h>
431+
432 // STL
433 #include <mutex>
434
435@@ -35,362 +42,156 @@
436 #include <signal.h>
437 #include <unistd.h>
438
439-// linux specific
440-#include <linux/oom.h>
441-
442-namespace
443-{
444-/**
445- * From man proc:
446- *
447- * This file can be used to adjust the score used to select which
448- * process should be killed in an out-of-memory (OOM) situation. The
449- * kernel uses this value for a bit-shift opera‐ tion of the process's
450- * oom_score value: valid values are in the range -16 to +15, plus the
451- * special value -17, which disables OOM-killing altogether for this
452- * process. A posi‐ tive score increases the likelihood of this process
453- * being killed by the OOM-killer; a negative score decreases the
454- * likelihood.
455- *
456- * The default value for this file is 0; a new process inherits its
457- * parent's oom_adj setting. A process must be privileged
458- * (CAP_SYS_RESOURCE) to update this file.
459-
460- * Since Linux 2.6.36, use of this file is deprecated in favor of
461- * /proc/[pid]/oom_score_adj.
462- */
463-struct OomAdjuster
464-{
465- static int disableOomKillerValue()
466- {
467- return OOM_DISABLE;
468- }
469-
470- static int minValue()
471- {
472- return OOM_ADJUST_MIN;
473- }
474-
475- static int maxValue()
476- {
477- return OOM_ADJUST_MAX;
478- }
479-
480- static OomAdjuster leastLikelyToBeKilled()
481- {
482+namespace plpp = core::posix::linux::proc::process;
483+
484+TaskController::OomController::OomController()
485+{
486+}
487+
488+void TaskController::OomController::ensureProcessLikelyToBeKilled(pid_t pid)
489+{
490+ // We avoid boundary values for oom_score_adj. For that, we
491+ // set it to 80% of the total available range.
492+ static const float defaultPercentage = 0.8;
493+
494+ core::posix::Process process(pid);
495+
496+ try
497+ {
498+ plpp::OomScoreAdj shellScore;
499+ core::posix::this_process::instance() >> shellScore;
500+
501+ plpp::OomScoreAdj processScore
502+ {
503+ static_cast<int>((plpp::OomScoreAdj::max_value() - shellScore.value) * defaultPercentage) + shellScore.value
504+ };
505+
506+ process << processScore;
507+ } catch(...)
508+ {
509+ // Accessing OomScoreAdj resulted in an exception being thrown.
510+ // Trying with the deprecated OomAdj now as a last resort.
511+ try
512+ {
513+ process << plpp::OomAdj{plpp::OomAdj::max_value()};
514+ } catch(...)
515+ {
516+ LOG("ensureProcessIsLikelyToBeKilled failed");
517+ }
518+ }
519+}
520+
521+void TaskController::OomController::ensureProcessUnlikelyToBeKilled(pid_t pid)
522+{
523+ // By system default, we set the oom_score_adj of Unity8 to -10 (via lightdm).
524+ // As we want to avoid that any app's oom_score_adj is <= Unity8's oom_score_adj,
525+ // we choose a default increase of +1.
526+ static const int default_increase = 1;
527+
528+ core::posix::Process process(pid);
529+
530+ try
531+ {
532+ plpp::OomScoreAdj shellScore;
533+ core::posix::this_process::instance() >> shellScore;
534+
535+ plpp::OomScoreAdj processScore
536+ {
537+ shellScore.value + default_increase
538+ };
539+
540+ process << processScore;
541+ } catch(...)
542+ {
543+ // Accessing OomScoreAdj resulted in an exception being thrown.
544+ // Trying with the deprecated OomAdj now as a last resort.
545 // By system default, we set the oom_score_adj of Unity8 to -10 (via lightdm).
546 // As we want to avoid that any app's oom_score_adj or oom_adj is <= Unity8's oom_score_adj,
547 // we choose a default value of -9 for oom_score_adj and 0 for oom_adj.
548- static const int default_value = 0;
549-
550- return OomAdjuster(default_value);
551- }
552-
553- static OomAdjuster mostLikelyToBeKilled()
554- {
555- return OomAdjuster(maxValue());
556- }
557-
558- OomAdjuster(int value) : value(value)
559- {
560- }
561-
562- bool isValid() const
563- {
564- return !(value < disableOomKillerValue() || value > maxValue());
565- }
566-
567- bool applyForPid(pid_t pid) const
568- {
569- auto fn = QString("/proc/%1/oom_adj").arg(pid);
570- QFile file(fn);
571-
572- if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
573- return false;
574-
575- QTextStream out(&file);
576- out << value;
577-
578- return true;
579- }
580-
581- int value;
582-};
583-
584-/**
585- * From man proc:
586- *
587- * This file can be used to adjust the badness heuristic used to
588- * select which process gets killed in out-of-memory conditions.
589- *
590- * The badness heuristic assigns a value to each candidate
591- * task ranging from 0 (never kill) to 1000 (always kill)
592- * to determine which process is targeted. The units are
593- * roughly a proportion along that range of allowed memory
594- * the process may allocate from, based on an estimation of
595- * its current memory and swap use. For example, if a task
596- * is using all allowed memory, its badness score will be
597- * 1000. If it is using half of its allowed memory, its
598- * score will be 500.
599- *
600- * There is an additional factor included in the badness score: root
601- * processes are given 3% extra memory over other tasks.
602- *
603- * The amount of "allowed" memory depends on the context in
604- * which the OOM-killer was called. If it is due to the
605- * memory assigned to the allocating task's cpuset being
606- * exhausted, the allowed memory represents the set of mems
607- * assigned to that cpuset (see cpuset(7)). If it is due
608- * to a mempolicy's node(s) being exhausted, the allowed
609- * memory represents the set of mempolicy nodes. If it is
610- * due to a memory limit (or swap limit) being reached, the
611- * allowed memory is that configured limit. Finally, if it
612- * is due to the entire system being out of memory, the
613- * allowed memory represents all allocatable resources.
614- *
615- * The value of oom_score_adj is added to the badness score before it
616- * is used to determine which task to kill. Acceptable values range
617- * from -1000 (OOM_SCORE_ADJ_MIN) to +1000 (OOM_SCORE_ADJ_MAX). This
618- * allows user space to control the preference for OOM-killing,
619- * ranging from always preferring a certain task or completely
620- * disabling it from OOM- killing. The lowest possible value, -1000,
621- * is equivalent to disabling OOM-killing entirely for that task,
622- * since it will always report a badness score of 0.
623- *
624- * Consequently, it is very simple for user space to define the amount
625- * of memory to consider for each task. Setting a oom_score_adj value
626- * of +500, for example, is roughly equiv‐ alent to allowing the
627- * remainder of tasks sharing the same system, cpuset, mempolicy, or
628- * memory controller resources to use at least 50% more memory. A
629- * value of -500, on the other hand, would be roughly equivalent to
630- * discounting 50% of the task's allowed memory from being considered
631- * as scoring against the task.
632- *
633- * For backward compatibility with previous kernels,
634- * /proc/[pid]/oom_adj can still be used to tune the badness score.
635- * Its value is scaled linearly with oom_score_adj.
636- *
637- * Writing to /proc/[pid]/oom_score_adj or
638- * /proc/[pid]/oom_adj will change the other with its
639- * scaled value.
640- */
641-struct OomScoreAdjuster
642-{
643- static int disableOomKillerValue()
644- {
645- return OOM_SCORE_ADJ_MIN;
646- }
647-
648- static int minValue()
649- {
650- return OOM_SCORE_ADJ_MIN;
651- }
652-
653- static int maxValue()
654- {
655- return OOM_SCORE_ADJ_MAX;
656- }
657-
658- static OomScoreAdjuster leastLikelyToBeKilled()
659- {
660- // By system default, we set the oom_score_adj of Unity8 to -10 (via lightdm).
661- // As we want to avoid that any app's oom_score_adj is <= Unity8's oom_score_adj,
662- // we choose a default value of -9, and a default increase of +1.
663- static const int default_value = -9;
664- static const int default_increase = 1;
665-
666-
667- // We could be way more clever here if we knew the distribution
668- // of oom_score_adj values of all app processes. However, we just
669- // make sure that the process is not ignored by the oom killer for now.
670- return OomScoreAdjuster(
671- OomScoreAdjuster::thisProcess().isValid() ?
672- OomScoreAdjuster::thisProcess().value + default_increase :
673- default_value);
674- }
675-
676- static OomScoreAdjuster mostLikelyToBeKilled()
677- {
678- // We avoid extremal values for oom_score_adj. For that, we
679- // set it to 80% of the total available range. If we cannot
680- // determine the oom_score_adj of the current process, i.e.,
681- // Unity8, we substract -200 by default.
682- static const float default_percentage = 0.8;
683- static const int default_decrease = -200;
684-
685- return OomScoreAdjuster(
686- OomScoreAdjuster::thisProcess().isValid() ?
687- (maxValue() - OomScoreAdjuster::thisProcess().value) * default_percentage + OomScoreAdjuster::thisProcess().value :
688- maxValue() - default_decrease);
689- }
690-
691- static const OomScoreAdjuster& thisProcess()
692- {
693- // Initialize as invalid.
694- static OomScoreAdjuster adjusterForThisProcess(minValue()-1);
695-
696- static std::once_flag query_once;
697- std::call_once(
698- query_once,
699- []()
700- {
701- pid_t pid = getpid();
702-
703- auto fn = QString("/proc/%1/oom_score_adj").arg(pid);
704- QFile file(fn);
705-
706- if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
707- return;
708-
709- QTextStream in(&file);
710- int value; in >> value;
711-
712- adjusterForThisProcess.value = value;
713- });
714-
715- return adjusterForThisProcess;
716- }
717-
718- OomScoreAdjuster(int value) : value(value)
719- {
720- }
721-
722- bool isValid() const
723- {
724- return !(value < disableOomKillerValue() || value > maxValue());
725- }
726-
727- bool applyForPid(pid_t pid) const
728- {
729- auto fn = QString("/proc/%1/oom_score_adj").arg(pid);
730- QFile file(fn);
731-
732- if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
733- return false;
734-
735- QTextStream out(&file);
736- out << value;
737-
738- return true;
739- }
740-
741- int value;
742-};
743-
744-void ensureProcessIsUnlikelyToBeKilled(pid_t pid)
745-{
746- if (!OomScoreAdjuster::leastLikelyToBeKilled().applyForPid(pid))
747- if (!OomAdjuster::leastLikelyToBeKilled().applyForPid(pid))
748+ static const int defaultValue = 0;
749+
750+ try
751+ {
752+ process << plpp::OomAdj{defaultValue};
753+ } catch(...)
754+ {
755 LOG("ensureProcessIsUnlikelyToBeKilled failed");
756+ }
757+ }
758 }
759
760-void ensureProcessIsLikelyToBeKilled(pid_t pid)
761+TaskController* theTaskController = nullptr;
762+
763+void cleanup_task_controller_singleton_instance()
764 {
765- if (!OomScoreAdjuster::mostLikelyToBeKilled().applyForPid(pid))
766- if (!OomAdjuster::mostLikelyToBeKilled().applyForPid(pid))
767- LOG("ensureProcessIsLikelyToBeKilled failed");
768-}
769-}
770-
771-TaskController* TaskController::m_theTaskController = nullptr;
772+ delete theTaskController;
773+}
774
775 TaskController* TaskController::singleton()
776 {
777- if (!m_theTaskController) {
778- m_theTaskController = new TaskController();
779+ if (!theTaskController) {
780+ theTaskController = new TaskController(
781+ nullptr,
782+ QSharedPointer<ApplicationController>(new upstart::ApplicationController()));
783+
784+ atexit(cleanup_task_controller_singleton_instance);
785 }
786- return m_theTaskController;
787+ return theTaskController;
788 }
789
790-TaskController::TaskController(QObject *parent) :
791- QObject(parent)
792+TaskController::TaskController(
793+ QObject* parent,
794+ const QSharedPointer<ApplicationController>& app_controller,
795+ const QSharedPointer<TaskController::OomController>& oom_controller) :
796+ QObject(parent),
797+ app_controller(app_controller),
798+ oom_controller(oom_controller)
799 {
800- preStartCallback = [](const gchar * appId, gpointer userData) {
801- Q_UNUSED(userData)
802- Q_EMIT TaskController::singleton()->processStartReport(QString(appId), false);
803- };
804-
805- startedCallback = [](const gchar * appId, gpointer userData) {
806- Q_UNUSED(userData)
807- pid_t pid = upstart_app_launch_get_primary_pid(appId);
808- ensureProcessIsUnlikelyToBeKilled(pid);
809- };
810-
811- stopCallback = [](const gchar * appId, gpointer userData) {
812- Q_UNUSED(userData)
813- Q_EMIT TaskController::singleton()->processStopped(QString(appId), false);
814- };
815-
816- focusCallback = [](const gchar * appId, gpointer userData) {
817- Q_UNUSED(userData)
818- pid_t pid = upstart_app_launch_get_primary_pid(appId);
819- ensureProcessIsUnlikelyToBeKilled(pid);
820- Q_EMIT TaskController::singleton()->requestFocus(QString(appId));
821- };
822-
823- resumeCallback = [](const gchar * appId, gpointer userData) {
824- Q_UNUSED(userData)
825- Q_EMIT TaskController::singleton()->requestResume(QString(appId));
826- };
827-
828- failureCallback = [](const gchar * appId, upstart_app_launch_app_failed_t failureType, gpointer userData) {
829- Q_UNUSED(userData)
830- if (failureType == UPSTART_APP_LAUNCH_APP_FAILED_CRASH) {
831- Q_EMIT TaskController::singleton()->processStopped(QString(appId), true);
832- } else if (failureType == UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE) {
833- Q_EMIT TaskController::singleton()->processStartReport(QString(appId), true);
834- } else {
835- LOG("TaskController: unknown failure type returned from upstart-app-launch");
836- }
837- Q_EMIT TaskController::singleton()->requestResume(QString(appId));
838- };
839-
840- upstart_app_launch_observer_add_app_starting(preStartCallback, nullptr);
841- upstart_app_launch_observer_add_app_started(startedCallback, nullptr);
842- upstart_app_launch_observer_add_app_stop(stopCallback, nullptr);
843- upstart_app_launch_observer_add_app_focus(focusCallback, nullptr);
844- upstart_app_launch_observer_add_app_resume(resumeCallback, nullptr);
845- upstart_app_launch_observer_add_app_failed(failureCallback, nullptr);
846+ connect(app_controller.data(),
847+ SIGNAL(applicationAboutToBeStarted(QString)),
848+ this,
849+ SLOT(onApplicationAboutToBeStarted(QString)));
850+
851+ connect(app_controller.data(),
852+ SIGNAL(applicationStarted(QString)),
853+ this,
854+ SLOT(onApplicationStarted(QString)));
855+
856+ connect(app_controller.data(),
857+ SIGNAL(applicationStopped(QString)),
858+ this,
859+ SLOT(onApplicationStopped(QString)));
860+
861+ connect(app_controller.data(),
862+ SIGNAL(applicationFocusRequest(QString)),
863+ this,
864+ SLOT(onApplicationFocusRequest(QString)));
865+
866+ connect(app_controller.data(),
867+ SIGNAL(applicationResumeRequest(QString)),
868+ this,
869+ SLOT(onApplicationResumeRequest(QString)));
870+
871+ connect(app_controller.data(),
872+ SIGNAL(applicationError(QString, ApplicationController::Error)),
873+ this,
874+ SLOT(onApplicationError(QString, ApplicationController::Error)));
875 }
876
877 TaskController::~TaskController()
878 {
879- upstart_app_launch_observer_delete_app_starting(preStartCallback, nullptr);
880- upstart_app_launch_observer_delete_app_started(startedCallback, nullptr);
881- upstart_app_launch_observer_delete_app_stop(stopCallback, nullptr);
882- upstart_app_launch_observer_delete_app_focus(focusCallback, nullptr);
883- upstart_app_launch_observer_delete_app_resume(resumeCallback, nullptr);
884- upstart_app_launch_observer_delete_app_failed(failureCallback, nullptr);
885 }
886
887 bool TaskController::start(const QString& appId, const QStringList& arguments)
888 {
889 DLOG("TaskController::start appId='%s'", qPrintable(appId));
890- gchar ** upstartArgs = nullptr;
891- bool result = false;
892-
893- // Convert arguments QStringList into format suitable for upstart-app-launch
894- upstartArgs = g_new0(gchar *, arguments.length());
895-
896- for (int i=0; i<arguments.length(); i++) {
897- upstartArgs[i] = arguments.at(i).toLatin1().data();
898- }
899-
900- result = upstart_app_launch_start_application(appId.toLatin1().constData(),
901- static_cast<const gchar * const *>(upstartArgs));
902- g_free(upstartArgs);
903-
904- DLOG_IF(!result, "TaskController::startApplication appId='%s' FAILED", qPrintable(appId));
905- return result;
906+ return app_controller->startApplicationWithAppIdAndArgs(appId, arguments);
907 }
908
909 bool TaskController::stop(const QString& appId)
910 {
911 DLOG("TaskController::stop appId='%s'", qPrintable(appId));
912- bool result = false;
913-
914- result = upstart_app_launch_stop_application(appId.toLatin1().constData());
915-
916+ auto result = app_controller->stopApplicationWithAppId(appId);
917 DLOG_IF(!result, "TaskController::stopApplication appId='%s' FAILED", qPrintable(appId));
918 return result;
919 }
920@@ -398,15 +199,14 @@
921 bool TaskController::appIdHasProcessId(const QString& appId, const quint64 pid)
922 {
923 DLOG("TaskController::isApplicationPid appId='%s', pid=%lld", qPrintable(appId), pid);
924- return upstart_app_launch_pid_in_app_id(pid, appId.toLatin1().constData());
925+ return app_controller->appIdHasProcessId(pid, appId);
926 }
927
928 bool TaskController::suspend(const QString& appId)
929 {
930 DLOG("TaskController::suspend (this=%p, application=%p)", this, qPrintable(appId));
931- pid_t pid = upstart_app_launch_get_primary_pid(appId.toLatin1().constData());
932-
933- ensureProcessIsLikelyToBeKilled(pid);
934+ auto pid = app_controller->primaryPidForAppId(appId);
935+ oom_controller->ensureProcessLikelyToBeKilled(pid);
936
937 if (pid) {
938 // We do assume that the app was launched by upstart and with that,
939@@ -422,9 +222,9 @@
940 bool TaskController::resume(const QString& appId)
941 {
942 DLOG("TaskController::resume (this=%p, application=%p)", this, qPrintable(appId));
943- pid_t pid = upstart_app_launch_get_primary_pid(appId.toLatin1().constData());
944+ auto pid = app_controller->primaryPidForAppId(appId);
945
946- ensureProcessIsUnlikelyToBeKilled(pid);
947+ oom_controller->ensureProcessUnlikelyToBeKilled(pid);
948
949 if (pid) {
950 // We do assume that the app was launched by upstart and with that,
951@@ -436,3 +236,47 @@
952 return false;
953 }
954 }
955+
956+void TaskController::onApplicationAboutToBeStarted(QString id)
957+{
958+ Q_EMIT processStartReport(id, false);
959+}
960+
961+void TaskController::onApplicationStarted(QString id)
962+{
963+ auto pid = app_controller->primaryPidForAppId(id);
964+ oom_controller->ensureProcessUnlikelyToBeKilled(pid);
965+}
966+
967+void TaskController::onApplicationStopped(QString id)
968+{
969+ Q_EMIT processStopped(id, false);
970+}
971+
972+void TaskController::onApplicationFocusRequest(QString id)
973+{
974+ auto pid = app_controller->primaryPidForAppId(id);
975+ oom_controller->ensureProcessUnlikelyToBeKilled(pid);
976+ Q_EMIT requestFocus(id);
977+}
978+
979+void TaskController::onApplicationResumeRequest(QString id)
980+{
981+ Q_EMIT requestResume(id);
982+}
983+
984+void TaskController::onApplicationError(QString id, ApplicationController::Error error)
985+{
986+ switch(error)
987+ {
988+ case ApplicationController::Error::APPLICATION_CRASHED:
989+ Q_EMIT processStopped(id, true);
990+ break;
991+ case ApplicationController::Error::APPLICATION_FAILED_TO_START:
992+ Q_EMIT processStartReport(id, true);
993+ break;
994+ }
995+
996+ // Is this really the signal we want to emit?
997+ Q_EMIT requestResume(id);
998+}
999
1000=== modified file 'src/modules/Unity/Application/taskcontroller.h'
1001--- src/modules/Unity/Application/taskcontroller.h 2013-12-05 17:11:36 +0000
1002+++ src/modules/Unity/Application/taskcontroller.h 2014-01-10 09:14:26 +0000
1003@@ -22,17 +22,32 @@
1004 #include <QObject>
1005
1006 #include "application.h"
1007-
1008-// upstart
1009-extern "C" {
1010- #include "upstart-app-launch.h"
1011-}
1012+#include "application_controller.h"
1013
1014 class TaskController : public QObject
1015 {
1016 Q_OBJECT
1017 public:
1018+
1019+ class OomController
1020+ {
1021+ public:
1022+ OomController();
1023+ OomController(const OomController&) = delete;
1024+ virtual ~OomController() = default;
1025+
1026+ OomController& operator=(const OomController&) = delete;
1027+
1028+ virtual void ensureProcessLikelyToBeKilled(pid_t);
1029+ virtual void ensureProcessUnlikelyToBeKilled(pid_t);
1030+ };
1031+
1032 static TaskController* singleton();
1033+
1034+ TaskController(
1035+ QObject* parent,
1036+ const QSharedPointer<ApplicationController>& app_controller,
1037+ const QSharedPointer<OomController>& oom_controller = QSharedPointer<OomController>(new OomController()));
1038 ~TaskController();
1039
1040 bool start(const QString& appId, const QStringList& args);
1041@@ -49,12 +64,18 @@
1042 void requestFocus(const QString& appId);
1043 void requestResume(const QString& appId);
1044
1045+private Q_SLOTS:
1046+ void onApplicationAboutToBeStarted(QString id);
1047+ void onApplicationStarted(QString id);
1048+ void onApplicationStopped(QString id);
1049+ void onApplicationFocusRequest(QString id);
1050+ void onApplicationResumeRequest(QString id);
1051+
1052+ void onApplicationError(QString id, ApplicationController::Error error);
1053+
1054 private:
1055- TaskController(QObject *parent = 0);
1056-
1057- static TaskController* m_theTaskController;
1058- upstart_app_launch_app_observer_t preStartCallback, startedCallback, stopCallback, focusCallback, resumeCallback;
1059- upstart_app_launch_app_failed_observer_t failureCallback;
1060+ QSharedPointer<ApplicationController> app_controller;
1061+ QSharedPointer<OomController> oom_controller;
1062 };
1063
1064 #endif // TASKCONTROLLER_H
1065
1066=== added directory 'src/modules/Unity/Application/upstart'
1067=== added file 'src/modules/Unity/Application/upstart/application_controller.cpp'
1068--- src/modules/Unity/Application/upstart/application_controller.cpp 1970-01-01 00:00:00 +0000
1069+++ src/modules/Unity/Application/upstart/application_controller.cpp 2014-01-10 09:14:26 +0000
1070@@ -0,0 +1,154 @@
1071+/*
1072+ * Copyright (C) 2013 Canonical, Ltd.
1073+ *
1074+ * This program is free software: you can redistribute it and/or modify it under
1075+ * the terms of the GNU Lesser General Public License version 3, as published by
1076+ * the Free Software Foundation.
1077+ *
1078+ * This program is distributed in the hope that it will be useful, but WITHOUT
1079+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1080+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1081+ * Lesser General Public License for more details.
1082+ *
1083+ * You should have received a copy of the GNU Lesser General Public License
1084+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1085+ *
1086+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
1087+ */
1088+
1089+#include "application_controller.h"
1090+
1091+// unity-mir
1092+#include <logging.h>
1093+
1094+// upstart
1095+extern "C" {
1096+ #include "upstart-app-launch.h"
1097+}
1098+
1099+struct upstart::ApplicationController::Private
1100+{
1101+ upstart_app_launch_app_observer_t preStartCallback = nullptr;
1102+ upstart_app_launch_app_observer_t startedCallback = nullptr;
1103+ upstart_app_launch_app_observer_t stopCallback = nullptr;
1104+ upstart_app_launch_app_observer_t focusCallback = nullptr;
1105+ upstart_app_launch_app_observer_t resumeCallback = nullptr;
1106+ upstart_app_launch_app_failed_observer_t failureCallback = nullptr;
1107+};
1108+
1109+upstart::ApplicationController::ApplicationController()
1110+ : ::ApplicationController(),
1111+ impl(new Private())
1112+{
1113+ impl->preStartCallback = [](const gchar * appId, gpointer userData) {
1114+ auto thiz = static_cast<upstart::ApplicationController*>(userData);
1115+ QMetaObject::invokeMethod(thiz,
1116+ "applicationAboutToBeStarted",
1117+ Qt::QueuedConnection, // This might happen on a different thread.
1118+ Q_ARG(QString, QString(appId)));
1119+ };
1120+
1121+ impl->startedCallback = [](const gchar * appId, gpointer userData) {
1122+ auto thiz = static_cast<upstart::ApplicationController*>(userData);
1123+ QMetaObject::invokeMethod(thiz,
1124+ "applicationStarted",
1125+ Qt::QueuedConnection, // This might happen on a different thread.
1126+ Q_ARG(QString, QString(appId)));
1127+ };
1128+
1129+ impl->stopCallback = [](const gchar * appId, gpointer userData) {
1130+ auto thiz = static_cast<upstart::ApplicationController*>(userData);
1131+ QMetaObject::invokeMethod(thiz,
1132+ "applicationStopped",
1133+ Qt::QueuedConnection, // This might happen on a different thread.
1134+ Q_ARG(QString, QString(appId)));
1135+ };
1136+
1137+ impl->focusCallback = [](const gchar * appId, gpointer userData) {
1138+ auto thiz = static_cast<upstart::ApplicationController*>(userData);
1139+ QMetaObject::invokeMethod(thiz,
1140+ "applicationFocusRequest",
1141+ Qt::QueuedConnection, // This might happen on a different thread.
1142+ Q_ARG(QString, QString(appId)));
1143+ };
1144+
1145+ impl->resumeCallback = [](const gchar * appId, gpointer userData) {
1146+ auto thiz = static_cast<upstart::ApplicationController*>(userData);
1147+ QMetaObject::invokeMethod(thiz,
1148+ "applicationResumeRequest",
1149+ Qt::QueuedConnection, // This might happen on a different thread.
1150+ Q_ARG(QString, QString(appId)));
1151+ };
1152+
1153+ impl->failureCallback = [](const gchar * appId, upstart_app_launch_app_failed_t failureType, gpointer userData) {
1154+ ApplicationController::Error error;
1155+ switch(failureType)
1156+ {
1157+ case UPSTART_APP_LAUNCH_APP_FAILED_CRASH: error = ApplicationController::Error::APPLICATION_CRASHED;
1158+ case UPSTART_APP_LAUNCH_APP_FAILED_START_FAILURE: error = ApplicationController::Error::APPLICATION_FAILED_TO_START;
1159+ }
1160+
1161+ auto thiz = static_cast<upstart::ApplicationController*>(userData);
1162+ QMetaObject::invokeMethod(thiz,
1163+ "applicationError",
1164+ Qt::QueuedConnection, // This might happen on a different thread.
1165+ Q_ARG(QString, QString(appId)),
1166+ Q_ARG(::ApplicationController::Error, error));
1167+ };
1168+
1169+ upstart_app_launch_observer_add_app_starting(impl->preStartCallback, this);
1170+ upstart_app_launch_observer_add_app_started(impl->startedCallback, this);
1171+ upstart_app_launch_observer_add_app_stop(impl->stopCallback, this);
1172+ upstart_app_launch_observer_add_app_focus(impl->focusCallback, this);
1173+ upstart_app_launch_observer_add_app_resume(impl->resumeCallback, this);
1174+ upstart_app_launch_observer_add_app_failed(impl->failureCallback, this);
1175+}
1176+
1177+upstart::ApplicationController::~ApplicationController()
1178+{
1179+ upstart_app_launch_observer_delete_app_starting(impl->preStartCallback, this);
1180+ upstart_app_launch_observer_delete_app_started(impl->startedCallback, this);
1181+ upstart_app_launch_observer_delete_app_stop(impl->stopCallback, this);
1182+ upstart_app_launch_observer_delete_app_focus(impl->focusCallback, this);
1183+ upstart_app_launch_observer_delete_app_resume(impl->resumeCallback, this);
1184+ upstart_app_launch_observer_delete_app_failed(impl->failureCallback, this);
1185+}
1186+
1187+pid_t upstart::ApplicationController::primaryPidForAppId(const QString& appId)
1188+{
1189+ auto pid = upstart_app_launch_get_primary_pid(appId.toLatin1().constData());
1190+ DLOG_IF(!pid, "ApplicationController::stopApplication appId='%s' FAILED", qPrintable(appId));
1191+
1192+ return pid;
1193+}
1194+
1195+bool upstart::ApplicationController::appIdHasProcessId(pid_t pid, const QString& appId)
1196+{
1197+ return upstart_app_launch_pid_in_app_id(pid, appId.toLatin1().constData());
1198+}
1199+
1200+bool upstart::ApplicationController::stopApplicationWithAppId(const QString& appId)
1201+{
1202+ auto result = upstart_app_launch_stop_application(appId.toLatin1().constData());
1203+ DLOG_IF(!result, "upstart::ApplicationController::stopApplicationWithAppId appId='%s' FAILED", qPrintable(appId));
1204+ return result;
1205+}
1206+
1207+bool upstart::ApplicationController::startApplicationWithAppIdAndArgs(const QString& appId, const QStringList& arguments)
1208+{
1209+ // Convert arguments QStringList into format suitable for upstart-app-launch
1210+ auto upstartArgs = g_new0(gchar *, arguments.length());
1211+
1212+ for (int i=0; i<arguments.length(); i++) {
1213+ upstartArgs[i] = arguments.at(i).toLatin1().data();
1214+ }
1215+
1216+ auto result = upstart_app_launch_start_application(
1217+ appId.toLatin1().constData(),
1218+ static_cast<const gchar * const *>(upstartArgs));
1219+
1220+ g_free(upstartArgs);
1221+
1222+ DLOG_IF(!result, "upstart::Application::Controller::startApplicationWithAppIdAndArgs appId='%s' FAILED", qPrintable(appId));
1223+ return result;
1224+}
1225
1226=== added file 'src/modules/Unity/Application/upstart/application_controller.h'
1227--- src/modules/Unity/Application/upstart/application_controller.h 1970-01-01 00:00:00 +0000
1228+++ src/modules/Unity/Application/upstart/application_controller.h 2014-01-10 09:14:26 +0000
1229@@ -0,0 +1,44 @@
1230+/*
1231+ * Copyright (C) 2013 Canonical, Ltd.
1232+ *
1233+ * This program is free software: you can redistribute it and/or modify it under
1234+ * the terms of the GNU Lesser General Public License version 3, as published by
1235+ * the Free Software Foundation.
1236+ *
1237+ * This program is distributed in the hope that it will be useful, but WITHOUT
1238+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1239+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1240+ * Lesser General Public License for more details.
1241+ *
1242+ * You should have received a copy of the GNU Lesser General Public License
1243+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1244+ *
1245+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
1246+ */
1247+
1248+#ifndef UPSTART_APPLICATION_CONTROLLER_H
1249+#define UPSTART_APPLICATION_CONTROLLER_H
1250+
1251+#include "../application_controller.h"
1252+
1253+namespace upstart
1254+{
1255+class ApplicationController : public ::ApplicationController
1256+{
1257+public:
1258+ ApplicationController();
1259+ ~ApplicationController();
1260+
1261+ pid_t primaryPidForAppId(const QString& appId);
1262+ bool appIdHasProcessId(pid_t pid, const QString& appId);
1263+
1264+ bool stopApplicationWithAppId(const QString& appId);
1265+ bool startApplicationWithAppIdAndArgs(const QString& appId, const QStringList& arguments);
1266+
1267+private:
1268+ struct Private;
1269+ QScopedPointer<Private> impl;
1270+};
1271+}
1272+
1273+#endif // UPSTART_APPLICATION_CONTROLLER_H
1274
1275=== added file 'src/modules/Unity/CMakeLists.txt'
1276--- src/modules/Unity/CMakeLists.txt 1970-01-01 00:00:00 +0000
1277+++ src/modules/Unity/CMakeLists.txt 2014-01-10 09:14:26 +0000
1278@@ -0,0 +1,1 @@
1279+add_subdirectory(Application)
1280
1281=== removed file 'src/modules/modules.pro'
1282--- src/modules/modules.pro 2013-08-29 14:46:43 +0000
1283+++ src/modules/modules.pro 1970-01-01 00:00:00 +0000
1284@@ -1,3 +0,0 @@
1285-TEMPLATE = subdirs
1286-
1287-SUBDIRS += Unity/Application
1288
1289=== removed file 'src/src.pro'
1290--- src/src.pro 2013-07-19 17:29:44 +0000
1291+++ src/src.pro 1970-01-01 00:00:00 +0000
1292@@ -1,6 +0,0 @@
1293-TEMPLATE = subdirs
1294-
1295-SUBDIRS += unity-mir \
1296- modules \
1297-
1298-modules.depends = unity-mir
1299
1300=== added file 'src/unity-mir/CMakeLists.txt'
1301--- src/unity-mir/CMakeLists.txt 1970-01-01 00:00:00 +0000
1302+++ src/unity-mir/CMakeLists.txt 2014-01-10 09:14:26 +0000
1303@@ -0,0 +1,72 @@
1304+include_directories(
1305+ ${MIRCOMMON_INCLUDE_DIRS}
1306+ ${MIRSERVER_INCLUDE_DIRS}
1307+ ${UBUNTU_PLATFORM_API_INCLUDE_DIRS}
1308+)
1309+
1310+set(
1311+ UNITY_MIR_HEADERS
1312+
1313+ dbusscreen.h
1314+ initialsurfaceplacementstrategy.h
1315+ qmirserverapplication.h
1316+ qmirserver.h
1317+ sessionauthorizer.h
1318+ sessionlistener.h
1319+ shellserverconfiguration.h
1320+ surfacefactory.h
1321+ surfaceconfigurator.h
1322+ logging.h
1323+ focussetter.h
1324+ serverstatuslistener.h)
1325+
1326+add_library(
1327+ unity-mir SHARED
1328+
1329+ dbusscreen.cpp
1330+ initialsurfaceplacementstrategy.cpp
1331+ qmirserverapplication.cpp
1332+ qmirserver.cpp
1333+ sessionauthorizer.cpp
1334+ sessionlistener.cpp
1335+ shellserverconfiguration.cpp
1336+ surfacefactory.cpp
1337+ surfaceconfigurator.cpp
1338+ focussetter.cpp
1339+ serverstatuslistener.cpp
1340+
1341+ ${UNITY_MIR_HEADERS})
1342+
1343+# We should not need this line according to the Qt5/CMake docs.
1344+# However, when removing it, include paths are not set and linking to Qt5 fails.
1345+qt5_use_modules(unity-mir Core Quick DBus)
1346+
1347+set_target_properties(
1348+ unity-mir
1349+
1350+ PROPERTIES
1351+ VERSION ${UNITY_MIR_VERSION_MAJOR}.${UNITY_MIR_VERSION_MINOR}.${UNITY_MIR_VERSION_PATCH}
1352+ SOVERSION ${UNITY_MIR_VERSION_MAJOR})
1353+
1354+target_link_libraries(
1355+ unity-mir
1356+
1357+ Qt5::Core
1358+ Qt5::Quick
1359+ Qt5::DBus
1360+
1361+ ${CMAKE_THREAD_LIBS_INIT}
1362+
1363+ ${UBUNTU_PLATFORM_API_LIBRARIES}
1364+ ${MIRCOMMON_LIBRARIES}
1365+ ${MIRSERVER_LIBRARIES}
1366+
1367+ ubuntu_application_api_mirserver)
1368+
1369+install(
1370+ TARGETS unity-mir
1371+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
1372+
1373+install(
1374+ FILES ${UNITY_MIR_HEADERS}
1375+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/unity-mir)
1376
1377=== modified file 'src/unity-mir/logging.h'
1378--- src/unity-mir/logging.h 2013-08-22 12:06:58 +0000
1379+++ src/unity-mir/logging.h 2014-01-10 09:14:26 +0000
1380@@ -17,6 +17,8 @@
1381 #ifndef UBUNTU_APPLICATION_PLUGIN_LOGGING_H
1382 #define UBUNTU_APPLICATION_PLUGIN_LOGGING_H
1383
1384+#pragma GCC diagnostic ignored "-Wformat"
1385+
1386 #include <QDebug>
1387
1388 // Logging and assertion macros.
1389
1390=== removed file 'src/unity-mir/unity-mir.pro'
1391--- src/unity-mir/unity-mir.pro 2013-11-18 16:05:56 +0000
1392+++ src/unity-mir/unity-mir.pro 1970-01-01 00:00:00 +0000
1393@@ -1,67 +0,0 @@
1394-TARGET = unity-mir
1395-TEMPLATE = lib
1396-
1397-QT += core quick dbus
1398-CONFIG += link_pkgconfig
1399-
1400-# CONFIG += c++11 # only enables C++0x
1401-QMAKE_CXXFLAGS = -std=c++11
1402-QMAKE_CXXFLAGS_RELEASE += -Werror # so no stop on warning in debug builds
1403-QMAKE_LFLAGS = -std=c++11 -Wl,-no-undefined
1404-
1405-PKGCONFIG += mircommon mirserver ubuntu-platform-api
1406-
1407-LIBS += -lubuntu_application_api_mirserver #FIXME platform-api pkgconfig should set this
1408-
1409-SOURCES += \
1410- dbusscreen.cpp \
1411- initialsurfaceplacementstrategy.cpp \
1412- qmirserverapplication.cpp \
1413- qmirserver.cpp \
1414- sessionauthorizer.cpp \
1415- sessionlistener.cpp \
1416- shellserverconfiguration.cpp \
1417- surfacefactory.cpp \
1418- surfaceconfigurator.cpp \
1419- focussetter.cpp \
1420- serverstatuslistener.cpp
1421-
1422-HEADERS += \
1423- dbusscreen.h \
1424- initialsurfaceplacementstrategy.h \
1425- qmirserverapplication.h \
1426- qmirserver.h \
1427- sessionauthorizer.h \
1428- sessionlistener.h \
1429- shellserverconfiguration.h \
1430- surfacefactory.h \
1431- surfaceconfigurator.h \
1432- logging.h \
1433- focussetter.h \
1434- serverstatuslistener.h
1435-
1436-target.path = $$[QT_INSTALL_LIBS]
1437-
1438-install_headers.files = qmirserverapplication.h \
1439- qmirserver.h \
1440- initialsurfaceplacementstrategy.h \
1441- sessionauthorizer.h \
1442- sessionlistener.h \
1443- shellserverconfiguration.h \
1444- surfacebuilder.h \
1445- surfacefactory.h
1446-install_headers.path = /usr/include/unity-mir
1447-
1448-### Generate pkg-config file
1449-CONFIG += create_pc create_prl no_install_prl
1450-
1451-QMAKE_PKGCONFIG_NAME = Unity-Mir
1452-QMAKE_PKGCONFIG_DESCRIPTION = Qt wrapper for Mir functionality required by Unity
1453-QMAKE_PKGCONFIG_PREFIX = $$INSTALLBASE
1454-QMAKE_PKGCONFIG_LIBDIR = $$target.path
1455-QMAKE_PKGCONFIG_INCDIR = $$installheaders.path
1456-QMAKE_PKGCONFIG_VERSION = $$VERSION
1457-QMAKE_PKGCONFIG_REQUIRES = ubuntu-platform-api mirclient mirserver Qt5Core
1458-QMAKE_PKGCONFIG_DESTDIR = pkgconfig
1459-
1460-INSTALLS += target install_headers
1461
1462=== added file 'tests/CMakeLists.txt'
1463--- tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
1464+++ tests/CMakeLists.txt 2014-01-10 09:14:26 +0000
1465@@ -0,0 +1,48 @@
1466+find_package(Qt5Core REQUIRED)
1467+find_package(Qt5Quick REQUIRED)
1468+find_package(Qt5DBus REQUIRED)
1469+
1470+# Build with system gmock and embedded gtest
1471+set (GMOCK_INCLUDE_DIR "/usr/include/gmock/include" CACHE PATH "gmock source include directory")
1472+set (GMOCK_SOURCE_DIR "/usr/src/gmock" CACHE PATH "gmock source directory")
1473+set (GTEST_INCLUDE_DIR "${GMOCK_SOURCE_DIR}/gtest/include" CACHE PATH "gtest source include directory")
1474+
1475+add_subdirectory(${GMOCK_SOURCE_DIR} "${CMAKE_CURRENT_BINARY_DIR}/gmock")
1476+
1477+#set (OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
1478+# Don't treat warnings as errors in 3rd_party/{gmock,cucumber-cpp}
1479+#string (REPLACE " -Werror " " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
1480+#find_package(Gtest REQUIRED)
1481+#include_directories(${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR})
1482+#set (CMAKE_CXX_FLAGS ${OLD_CMAKE_CXX_FLAGS})
1483+
1484+include_directories(
1485+ ${CMAKE_SOURCE_DIR}/src/modules
1486+ ${GMOCK_INCLUDE_DIR}
1487+ ${GTEST_INCLUDE_DIR}
1488+)
1489+
1490+add_executable(
1491+ taskcontroller_test
1492+ taskcontroller_test.cpp
1493+)
1494+
1495+# We should not need this line according to the Qt5/CMake docs.
1496+# However, when removing it, include paths are not set and linking to Qt5 fails.
1497+qt5_use_modules(taskcontroller_test Core Quick DBus)
1498+
1499+target_link_libraries(
1500+ taskcontroller_test
1501+
1502+ unityapplicationplugin
1503+
1504+ Qt5::Core
1505+ Qt5::Quick
1506+ Qt5::DBus
1507+
1508+ gtest
1509+ gtest_main
1510+ gmock
1511+)
1512+
1513+add_test(taskcontroller_test ${CMAKE_CURRENT_BINARY_DIR}/taskcontroller_test)
1514
1515=== added file 'tests/taskcontroller_test.cpp'
1516--- tests/taskcontroller_test.cpp 1970-01-01 00:00:00 +0000
1517+++ tests/taskcontroller_test.cpp 2014-01-10 09:14:26 +0000
1518@@ -0,0 +1,211 @@
1519+/*
1520+ * Copyright (C) 2013 Canonical, Ltd.
1521+ *
1522+ * This program is free software: you can redistribute it and/or modify it under
1523+ * the terms of the GNU Lesser General Public License version 3, as published by
1524+ * the Free Software Foundation.
1525+ *
1526+ * This program is distributed in the hope that it will be useful, but WITHOUT
1527+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
1528+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1529+ * Lesser General Public License for more details.
1530+ *
1531+ * You should have received a copy of the GNU Lesser General Public License
1532+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1533+ *
1534+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
1535+ *
1536+ */
1537+
1538+#include <Unity/Application/taskcontroller.h>
1539+
1540+#include <gmock/gmock.h>
1541+#include <gtest/gtest.h>
1542+
1543+namespace
1544+{
1545+struct MockOomController : public TaskController::OomController
1546+{
1547+ MOCK_METHOD1(ensureProcessLikelyToBeKilled, void(pid_t));
1548+ MOCK_METHOD1(ensureProcessUnlikelyToBeKilled, void(pid_t));
1549+};
1550+
1551+struct TriggerableApplicationController : public ApplicationController
1552+{
1553+ void triggerApplicationStarted(const QString& appId)
1554+ {
1555+ Q_EMIT applicationStarted(appId);
1556+ }
1557+
1558+ void triggerApplicationStopped(const QString& appId)
1559+ {
1560+ Q_EMIT applicationStopped(appId);
1561+ }
1562+
1563+ void triggerApplicationFocusRequest(const QString& appId)
1564+ {
1565+ Q_EMIT applicationFocusRequest(appId);
1566+ }
1567+
1568+ MOCK_METHOD1(primaryPidForAppId, pid_t (const QString&));
1569+ MOCK_METHOD2(appIdHasProcessId, bool(pid_t, const QString&));
1570+ MOCK_METHOD1(stopApplicationWithAppId, bool(const QString&));
1571+ MOCK_METHOD2(startApplicationWithAppIdAndArgs, bool(const QString&, const QStringList&));
1572+};
1573+}
1574+
1575+TEST(TaskController, startingAnApplicationCallsCorrectlyIntoApplicationController)
1576+{
1577+ using namespace ::testing;
1578+
1579+ const QString appId{"com.canonical.does.not.exist"};
1580+
1581+ testing::NiceMock<TriggerableApplicationController> appController;
1582+ QSharedPointer<TriggerableApplicationController> appControllerPtr(
1583+ &appController,
1584+ [](ApplicationController*){});
1585+
1586+ EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(appId, QStringList())).Times(1).WillRepeatedly(Return(true));
1587+
1588+ testing::NiceMock<MockOomController> oomController;
1589+ QSharedPointer<TaskController::OomController> oomControllerPtr(
1590+ &oomController,
1591+ [](TaskController::OomController*){});
1592+
1593+ TaskController taskController(nullptr,
1594+ appControllerPtr,
1595+ oomControllerPtr);
1596+
1597+ taskController.start("com.canonical.does.not.exist", QStringList());
1598+}
1599+
1600+TEST(TaskController, stoppingAnApplicationCallsCorrectlyIntoApplicationController)
1601+{
1602+ using namespace ::testing;
1603+
1604+ const QString appId{"com.canonical.does.not.exist"};
1605+
1606+ testing::NiceMock<TriggerableApplicationController> appController;
1607+ QSharedPointer<TriggerableApplicationController> appControllerPtr(
1608+ &appController,
1609+ [](ApplicationController*){});
1610+
1611+ EXPECT_CALL(appController, stopApplicationWithAppId(appId)).Times(1).WillRepeatedly(Return(true));
1612+
1613+ testing::NiceMock<MockOomController> oomController;
1614+ QSharedPointer<TaskController::OomController> oomControllerPtr(
1615+ &oomController,
1616+ [](TaskController::OomController*){});
1617+
1618+ TaskController taskController(nullptr,
1619+ appControllerPtr,
1620+ oomControllerPtr);
1621+
1622+ taskController.stop("com.canonical.does.not.exist");
1623+}
1624+
1625+TEST(TaskController, suspendingAnApplicationAdjustsOomScoreForCorrectPid)
1626+{
1627+ using namespace ::testing;
1628+
1629+ const QString appId{"com.canonical.does.not.exist"};
1630+
1631+ testing::NiceMock<TriggerableApplicationController> appController;
1632+ QSharedPointer<TriggerableApplicationController> appControllerPtr(
1633+ &appController,
1634+ [](ApplicationController*){});
1635+
1636+ EXPECT_CALL(appController, primaryPidForAppId(appId)).Times(1).WillRepeatedly(Return(-1));
1637+
1638+ testing::NiceMock<MockOomController> oomController;
1639+ QSharedPointer<TaskController::OomController> oomControllerPtr(
1640+ &oomController,
1641+ [](TaskController::OomController*){});
1642+
1643+ EXPECT_CALL(oomController, ensureProcessLikelyToBeKilled(-1)).Times(1);
1644+
1645+ TaskController taskController(nullptr,
1646+ appControllerPtr,
1647+ oomControllerPtr);
1648+
1649+ taskController.suspend("com.canonical.does.not.exist");
1650+}
1651+
1652+TEST(TaskController, resumingAnApplicationAdjustsOomScoreForCorrectPid)
1653+{
1654+ using namespace ::testing;
1655+
1656+ const QString appId{"com.canonical.does.not.exist"};
1657+
1658+ testing::NiceMock<TriggerableApplicationController> appController;
1659+ QSharedPointer<TriggerableApplicationController> appControllerPtr(
1660+ &appController,
1661+ [](ApplicationController*){});
1662+
1663+ EXPECT_CALL(appController, primaryPidForAppId(appId)).Times(1).WillRepeatedly(Return(-1));
1664+
1665+ testing::NiceMock<MockOomController> oomController;
1666+ QSharedPointer<TaskController::OomController> oomControllerPtr(
1667+ &oomController,
1668+ [](TaskController::OomController*){});
1669+
1670+ EXPECT_CALL(oomController, ensureProcessUnlikelyToBeKilled(-1)).Times(1);
1671+
1672+ TaskController taskController(nullptr,
1673+ appControllerPtr,
1674+ oomControllerPtr);
1675+
1676+ taskController.resume("com.canonical.does.not.exist");
1677+}
1678+
1679+TEST(TaskController, aStartedApplicationIsOomScoreAdjusted)
1680+{
1681+ using namespace ::testing;
1682+
1683+ const QString appId{"com.canonical.does.not.exist"};
1684+
1685+ testing::NiceMock<TriggerableApplicationController> appController;
1686+ QSharedPointer<TriggerableApplicationController> appControllerPtr(
1687+ &appController,
1688+ [](ApplicationController*){});
1689+ EXPECT_CALL(appController, primaryPidForAppId(appId)).Times(1).WillRepeatedly(Return(42));
1690+
1691+ testing::NiceMock<MockOomController> oomController;
1692+ QSharedPointer<TaskController::OomController> oomControllerPtr(
1693+ &oomController,
1694+ [](TaskController::OomController*){});
1695+
1696+ EXPECT_CALL(oomController, ensureProcessUnlikelyToBeKilled(42)).Times(1);
1697+
1698+ TaskController taskController(nullptr,
1699+ appControllerPtr,
1700+ oomControllerPtr);
1701+
1702+ appControllerPtr->triggerApplicationStarted("com.canonical.does.not.exist");
1703+}
1704+
1705+TEST(TaskController, aFocusedApplicationIsOomScoreAdjusted)
1706+{
1707+ using namespace ::testing;
1708+
1709+ const QString appId{"com.canonical.does.not.exist"};
1710+
1711+ testing::NiceMock<TriggerableApplicationController> appController;
1712+ QSharedPointer<TriggerableApplicationController> appControllerPtr(
1713+ &appController,
1714+ [](ApplicationController*){});
1715+ EXPECT_CALL(appController, primaryPidForAppId(appId)).Times(1).WillRepeatedly(Return(42));
1716+
1717+ testing::NiceMock<MockOomController> oomController;
1718+ QSharedPointer<TaskController::OomController> oomControllerPtr(
1719+ &oomController,
1720+ [](TaskController::OomController*){});
1721+
1722+ EXPECT_CALL(oomController, ensureProcessUnlikelyToBeKilled(42)).Times(1);
1723+
1724+ TaskController taskController(nullptr,
1725+ appControllerPtr,
1726+ oomControllerPtr);
1727+
1728+ appControllerPtr->triggerApplicationFocusRequest("com.canonical.does.not.exist");
1729+}
1730
1731=== removed file 'tests/tests.pro'
1732=== removed file 'unity-mir.pro'
1733--- unity-mir.pro 2013-09-26 09:48:22 +0000
1734+++ unity-mir.pro 1970-01-01 00:00:00 +0000
1735@@ -1,2 +0,0 @@
1736-TEMPLATE = subdirs
1737-SUBDIRS = src #tests

Subscribers

People subscribed via source and target branches