Mir

Merge lp:~albaguirre/mir/fix-1498550 into lp:mir

Proposed by Alberto Aguirre
Status: Merged
Approved by: Alberto Aguirre
Approved revision: no longer in the source branch.
Merged at revision: 2997
Proposed branch: lp:~albaguirre/mir/fix-1498550
Merge into: lp:mir
Diff against target: 219 lines (+74/-24)
6 files modified
src/platforms/android/server/display.cpp (+2/-1)
src/platforms/android/server/display_device_exceptions.h (+17/-10)
src/platforms/android/server/display_group.cpp (+21/-4)
src/platforms/android/server/display_group.h (+7/-1)
src/platforms/android/server/real_hwc_wrapper.cpp (+10/-6)
tests/unit-tests/graphics/android/test_display_group.cpp (+17/-2)
To merge this branch: bzr merge lp:~albaguirre/mir/fix-1498550
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Kevin DuBois (community) Approve
Alan Griffiths Approve
Alexandros Frantzis (community) Approve
Review via email: mp+273102@code.launchpad.net

Commit message

[android] Attempt to recover from errors when posting to an external display

Description of the change

[android] Attempt to recover from errors when posting to an external display

I had some additional logic to handle scenario 3, but with latest lp:mir, it seems scenario 3's root cause may be tied to some object lifetime issues seen in a nested configuration (in which either "pure virtual method call" errors are seen, or exceptions after getting EGL_BADSURFACE.

I also opted to reuse the "hotplug" code path (I had some other logic that just attempted to restart the compositor threads) when handling the external display errors so that display configuration is forced - which in turns restarts the compositor threads (which is what is needed for recovery). This makes the diff much more smaller :)

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alexandros Frantzis (afrantzis) wrote :

Looks good.

Nit:

+ std::function<void()> error_handler

Could be const&

review: Approve
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

Without looking at implementation and usage details the design isn't clear.

You have:

    std::function<void()> error_handler

Now is that something that is to be called in a catch block? In which case an implementer might expect to do...

    try
    {
      rethrow;
    }
    ...
    catch (std::error const& x)
    {
      ...
    }

...to regain exception information (either for logging or for decision making).

But if needn't be in a catch block then the rethrow idiom is a bad idea.

And how much context does the handler need? Would it be better as void (*error_handler)(char const* error_message)

Whichever option is intended could be better expressed in the code.

E.g.

using CurrentExceptionHandler = std::function<void()>

    CurrentExceptionHandler error_handler

review: Needs Information
Revision history for this message
Alberto Aguirre (albaguirre) wrote :

"Now is that something that is to be called in a catch block?"

Yes.

Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

> "Now is that something that is to be called in a catch block?"
>
> Yes.

could be better expressed in the code (or at least in a comment).

review: Needs Fixing
Revision history for this message
Alan Griffiths (alan-griffiths) wrote :

OK

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

lgtm too

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/platforms/android/server/display.cpp'
2--- src/platforms/android/server/display.cpp 2015-10-05 08:19:39 +0000
3+++ src/platforms/android/server/display.cpp 2015-10-06 15:33:24 +0000
4@@ -166,7 +166,8 @@
5 gl_program_factory,
6 gl_context,
7 geom::Displacement{0,0},
8- overlay_option)),
9+ overlay_option),
10+ [this] { on_hotplug(); }), //Recover from exception by forcing a configuration change
11 overlay_option(overlay_option)
12 {
13 //Some drivers (depending on kernel state) incorrectly report an error code indicating that the display is already on. Ignore the first failure.
14
15=== renamed file 'src/platforms/android/server/display_disconnected_exception.h' => 'src/platforms/android/server/display_device_exceptions.h'
16--- src/platforms/android/server/display_disconnected_exception.h 2015-09-23 19:09:59 +0000
17+++ src/platforms/android/server/display_device_exceptions.h 2015-10-06 15:33:24 +0000
18@@ -16,10 +16,11 @@
19 * Authored by: Alberto Aguirre <alberto.aguirre@canonical.com>
20 */
21
22-#ifndef MIR_GRAPHICS_ANDROID_DISPLAY_DISCONNECTED_EXCEPTION_H_
23-#define MIR_GRAPHICS_ANDROID_DISPLAY_DISCONNECTED_EXCEPTION_H_
24+#ifndef MIR_GRAPHICS_ANDROID_DISPLAY_DEVICE_EXCEPTIONS_H_
25+#define MIR_GRAPHICS_ANDROID_DISPLAY_DEVICE_EXCEPTIONS_H_
26
27 #include <stdexcept>
28+#include <string>
29
30 namespace mir
31 {
32@@ -31,11 +32,17 @@
33 class DisplayDisconnectedException : public std::runtime_error
34 {
35 public:
36- DisplayDisconnectedException() : std::runtime_error("display disconnected") {}
37-};
38-
39-}
40-}
41-}
42-
43-#endif /* MIR_GRAPHICS_ANDROID_DISPLAY_DISCONNECTED_EXCEPTION_H_ */
44+ DisplayDisconnectedException(std::string const& message) : std::runtime_error(message) {}
45+};
46+
47+class ExternalDisplayError : public std::runtime_error
48+{
49+public:
50+ ExternalDisplayError(std::string const& message) : std::runtime_error(message) {}
51+};
52+
53+}
54+}
55+}
56+
57+#endif /* MIR_GRAPHICS_ANDROID_DISPLAY_DEVICE_EXCEPTIONS_H_ */
58
59=== modified file 'src/platforms/android/server/display_group.cpp'
60--- src/platforms/android/server/display_group.cpp 2015-09-23 19:09:59 +0000
61+++ src/platforms/android/server/display_group.cpp 2015-10-06 15:33:24 +0000
62@@ -18,7 +18,7 @@
63
64 #include "display_group.h"
65 #include "configurable_display_buffer.h"
66-#include "display_disconnected_exception.h"
67+#include "display_device_exceptions.h"
68 #include <boost/throw_exception.hpp>
69 #include <stdexcept>
70
71@@ -28,12 +28,21 @@
72
73 mga::DisplayGroup::DisplayGroup(
74 std::shared_ptr<mga::DisplayDevice> const& device,
75- std::unique_ptr<mga::ConfigurableDisplayBuffer> primary_buffer) :
76- device(device)
77+ std::unique_ptr<mga::ConfigurableDisplayBuffer> primary_buffer,
78+ ExceptionHandler const& exception_handler) :
79+ device(device),
80+ exception_handler(exception_handler)
81 {
82 dbs.emplace(std::make_pair(mga::DisplayName::primary, std::move(primary_buffer)));
83 }
84
85+mga::DisplayGroup::DisplayGroup(
86+ std::shared_ptr<mga::DisplayDevice> const& device,
87+ std::unique_ptr<mga::ConfigurableDisplayBuffer> primary_buffer)
88+ : DisplayGroup(device, std::move(primary_buffer), []{})
89+{
90+}
91+
92 void mga::DisplayGroup::for_each_display_buffer(std::function<void(mg::DisplayBuffer&)> const& f)
93 {
94 std::unique_lock<decltype(guard)> lk(guard);
95@@ -87,10 +96,18 @@
96 {
97 device->commit(contents);
98 }
99- catch (mga::DisplayDisconnectedException& e)
100+ catch (mga::DisplayDisconnectedException const&)
101 {
102 //Ignore disconnect errors as they are not fatal
103 }
104+ catch (mga::ExternalDisplayError const&)
105+ {
106+ //NOTE: We allow Display to inject an error handler (which can then attempt to recover
107+ // from this error) as post is called directly by the compositor and we don't want to propagate
108+ // handling of android platform specific exceptions in mir core.
109+ exception_handler();
110+ }
111+
112 }
113
114 std::chrono::milliseconds mga::DisplayGroup::recommended_sleep() const
115
116=== modified file 'src/platforms/android/server/display_group.h'
117--- src/platforms/android/server/display_group.h 2015-09-23 19:09:59 +0000
118+++ src/platforms/android/server/display_group.h 2015-10-06 15:33:24 +0000
119@@ -38,9 +38,14 @@
120 class DisplayGroup : public graphics::DisplaySyncGroup
121 {
122 public:
123+ using ExceptionHandler = std::function<void()>;
124 DisplayGroup(
125 std::shared_ptr<DisplayDevice> const& device,
126- std::unique_ptr<ConfigurableDisplayBuffer> primary_buffer);
127+ std::unique_ptr<ConfigurableDisplayBuffer> primary_buffer,
128+ ExceptionHandler const& handler);
129+ DisplayGroup(
130+ std::shared_ptr<DisplayDevice> const& device,
131+ std::unique_ptr<ConfigurableDisplayBuffer> primary_buffer);
132
133 void for_each_display_buffer(std::function<void(graphics::DisplayBuffer&)> const& f) override;
134 void post() override;
135@@ -55,6 +60,7 @@
136 std::mutex mutable guard;
137 std::shared_ptr<DisplayDevice> const device;
138 std::map<DisplayName, std::unique_ptr<ConfigurableDisplayBuffer>> dbs;
139+ ExceptionHandler const exception_handler;
140 };
141
142 }
143
144=== modified file 'src/platforms/android/server/real_hwc_wrapper.cpp'
145--- src/platforms/android/server/real_hwc_wrapper.cpp 2015-09-23 19:09:59 +0000
146+++ src/platforms/android/server/real_hwc_wrapper.cpp 2015-10-06 15:33:24 +0000
147@@ -18,7 +18,7 @@
148
149 #include "real_hwc_wrapper.h"
150 #include "hwc_report.h"
151-#include "display_disconnected_exception.h"
152+#include "display_device_exceptions.h"
153 #include <boost/throw_exception.hpp>
154 #include <stdexcept>
155 #include <sstream>
156@@ -120,13 +120,17 @@
157 if (auto rc = hwc_device->set(hwc_device.get(), num_displays,
158 const_cast<hwc_display_contents_1**>(displays.data())))
159 {
160- if (num_displays > 1 && !display_connected(DisplayName::external))
161- {
162- BOOST_THROW_EXCEPTION(mga::DisplayDisconnectedException());
163- }
164-
165 std::stringstream ss;
166 ss << "error during hwc set(). rc = " << std::hex << rc;
167+
168+ if (num_displays > 1)
169+ {
170+ if (!display_connected(DisplayName::external))
171+ BOOST_THROW_EXCEPTION(mga::DisplayDisconnectedException(ss.str()));
172+ else
173+ BOOST_THROW_EXCEPTION(mga::ExternalDisplayError(ss.str()));
174+ }
175+
176 BOOST_THROW_EXCEPTION(std::runtime_error(ss.str()));
177 }
178 report->report_set_done(displays);
179
180=== modified file 'tests/unit-tests/graphics/android/test_display_group.cpp'
181--- tests/unit-tests/graphics/android/test_display_group.cpp 2015-10-01 08:58:30 +0000
182+++ tests/unit-tests/graphics/android/test_display_group.cpp 2015-10-06 15:33:24 +0000
183@@ -18,7 +18,7 @@
184
185 #include "src/platforms/android/server/configurable_display_buffer.h"
186 #include "src/platforms/android/server/display_group.h"
187-#include "src/platforms/android/server/display_disconnected_exception.h"
188+#include "src/platforms/android/server/display_device_exceptions.h"
189 #include "mir/test/doubles/mock_display_device.h"
190 #include "mir/test/doubles/stub_renderable_list_compositor.h"
191 #include "mir/test/doubles/stub_swapping_gl_context.h"
192@@ -91,7 +91,7 @@
193 NiceMock<mtd::MockDisplayDevice> mock_device;
194 mga::DisplayGroup group(mt::fake_shared(mock_device), std::make_unique<StubConfigurableDB>());
195 EXPECT_CALL(mock_device, commit(_))
196- .WillOnce(Throw(mga::DisplayDisconnectedException()))
197+ .WillOnce(Throw(mga::DisplayDisconnectedException("")))
198 .WillOnce(Throw(std::runtime_error("")));
199
200 EXPECT_NO_THROW({group.post();});
201@@ -100,3 +100,18 @@
202 group.post();
203 }, std::runtime_error);
204 }
205+
206+TEST(DisplayGroup, calls_error_handler_on_external_display_error)
207+{
208+ using namespace testing;
209+ NiceMock<mtd::MockDisplayDevice> mock_device;
210+ bool error_handler_called{false};
211+
212+ mga::DisplayGroup group(mt::fake_shared(mock_device), std::make_unique<StubConfigurableDB>(),
213+ [&error_handler_called] { error_handler_called = true; });
214+ EXPECT_CALL(mock_device, commit(_))
215+ .WillOnce(Throw(mga::ExternalDisplayError("")));
216+
217+ EXPECT_NO_THROW({group.post();});
218+ EXPECT_TRUE(error_handler_called);
219+}

Subscribers

People subscribed via source and target branches