Merge lp:~albaguirre/mir/fix-1465883 into lp:mir
- fix-1465883
- Merge into development-branch
Status: | Merged |
---|---|
Approved by: | Alberto Aguirre |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2674 |
Proposed branch: | lp:~albaguirre/mir/fix-1465883 |
Merge into: | lp:mir |
Diff against target: |
1413 lines (+308/-238) 12 files modified
src/client/buffer_stream.cpp (+38/-37) src/client/buffer_stream.h (+3/-3) src/client/make_protobuf_object.h (+42/-0) src/client/mir_connection.cpp (+56/-49) src/client/mir_connection.h (+8/-6) src/client/mir_prompt_session.cpp (+21/-15) src/client/mir_prompt_session.h (+5/-5) src/client/mir_screencast.cpp (+24/-21) src/client/mir_screencast.h (+4/-2) src/client/mir_surface.cpp (+83/-76) src/client/mir_surface.h (+6/-7) src/client/rpc/mir_protobuf_rpc_channel.cpp (+18/-17) |
To merge this branch: | bzr merge lp:~albaguirre/mir/fix-1465883 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alan Griffiths | Approve | ||
Chris Halse Rogers | Approve | ||
Daniel van Vugt | Needs Fixing | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+262160@code.launchpad.net |
Commit message
Avoid allocating mir::protobuf objects on the stack
When an addition is made to a protobuf message, a stack allocation of such object may differ from what the destructor of that message is expecting as the destructor is defined by libmirprotobuf and the allocation may have been made from an older definition of the message (by an older mirclient library for example) which can lead to stack corruption.
Ideally, the mirprotobuf library would have versioned symbols and have the ability to be loaded in parallel to a previous version but that's not currently possible.
As an alternative, avoid allocating mir defined protobuf objects on the stack and instead use the xxx::default_
Description of the change
Avoid allocating mir::protobuf objects on the stack
When an addition is made to a protobuf message, a stack allocation of such object may differ from what the destructor of that message is expecting as the destructor is defined by libmirprotobuf and the allocation may have been made from an older definition of the message (by an older mirclient library for example) which can lead to stack corruption.
Ideally, the mirprotobuf library would have versioned symbols and have the ability to be loaded in parallel to a previous version but that's not currently possible.
As an alternative, avoid allocating mir defined protobuf objects on the stack and instead use the xxx::default_
PS Jenkins bot (ps-jenkins) wrote : | # |
Daniel van Vugt (vanvugt) wrote : | # |
Slightly scary no one figured this out earlier.
A worse way to think of the bug is: If a new field is added to a message then any existing code will try to construct that message on the stack using its old (smaller) size while Protobuf itself fills out the new fields (which we didn't allow for in the stack allocation). Hence stack corruption.
The solution presented here however fails to work in all cases of ABI breaks such as when a member is removed from the middle of the object. Not likely, but there is a better option...
The issue is really that we're breaking MIRPROTOBUF_ABI but have never thought to bump it. If it was bumped any any change to message sizes/structure then everyone would always be linked to a version that is safe for them. And bumping MIRPROTOBUF_ABI would mean we could keep our nice fast stack variables.
Daniel van Vugt (vanvugt) wrote : | # |
So I think Disapprove/Needs fixing. A simple bump of MIRPROTOBUF_ABI will solve it more reliably and give us more efficient code. Unless anyone can prove there's a protobuf issue preventing us from doing that.
Daniel van Vugt (vanvugt) wrote : | # |
It's also worth noting you don't need versioned symbols at all if your major ABI number is changing instead.
Chris Halse Rogers (raof) wrote : | # |
There *is* a protobuf issue preventing us from doing that; see for example the failures on input-methods-
The issue is that protobuf will abort() if it's loaded twice, and bumping mirprotobuf ABI ensures that it's loaded twice. Otherwise we wouldn't be building libmirprotobuf.so at all, and would be statically linking it as nature intended.
Chris Halse Rogers (raof) wrote : | # |
So, urgh. Yeah, this is better than what we've got.
Is there any obvious way to test that we don't stack-create protobuf objects? It'd be nice to have a test, but I can't think of one.
Alan Griffiths (alan-griffiths) wrote : | # |
> So I think Disapprove/Needs fixing. A simple bump of MIRPROTOBUF_ABI will
> solve it more reliably and give us more efficient code. Unless anyone can
> prove there's a protobuf issue preventing us from doing that.
It really isn't that simple: protobuf has a number of issues in this area. Essentially, we can only have one protobuf instantiation in process.
We've "got away" with it while the client ABI has remained at 8 (as only the latest limbirprotobuf gets loaded). Now we're proposing 9 we need to keep the same limbirprotobuf version.
Alexandros has tried to upstream some fixes to protobuf, and Kevin and Chris have recently run into problems.
AFAICS the approach proposed here is the least bad of the feasible options.
Alberto Aguirre (albaguirre) wrote : | # |
@Daniel,
As others have said, yes there are protobuf issues preventing loading two versions in the same process (for more comments see Chris branch https:/
Loading two versions of protobuf in the same process is more common than is apparent at first glance, because the mesa client platform module links against libmirclient.
Indeed, just by probing the modules, a client that links against libmirclient8, will end up loading libmirprotobuf.so.1 since the module will load libmirclient9 (which is linked to libmirprotobuf.
Alberto Aguirre (albaguirre) wrote : | # |
"The solution presented here however fails to work in all cases of ABI breaks such as when a member is removed from the middle of the object. Not likely, but there is a better option..."
This is true, we still need to tread carefully when modifying protobuf message definitions.
Preview Diff
1 | === modified file 'src/client/buffer_stream.cpp' |
2 | --- src/client/buffer_stream.cpp 2015-06-03 19:17:55 +0000 |
3 | +++ src/client/buffer_stream.cpp 2015-06-16 23:39:42 +0000 |
4 | @@ -19,6 +19,7 @@ |
5 | #define MIR_LOG_COMPONENT "MirBufferStream" |
6 | |
7 | #include "buffer_stream.h" |
8 | +#include "make_protobuf_object.h" |
9 | |
10 | #include "mir_connection.h" |
11 | #include "mir/frontend/client_constants.h" |
12 | @@ -97,11 +98,11 @@ |
13 | display_server(server), |
14 | mode(mode), |
15 | client_platform(client_platform), |
16 | - protobuf_bs(protobuf_bs), |
17 | + protobuf_bs{mcl::make_protobuf_object<mir::protobuf::BufferStream>(protobuf_bs)}, |
18 | buffer_depository{client_platform->create_buffer_factory(), mir::frontend::client_buffer_cache_size}, |
19 | swap_interval_(1), |
20 | - perf_report(perf_report) |
21 | - |
22 | + perf_report(perf_report), |
23 | + protobuf_void{mcl::make_protobuf_object<mir::protobuf::Void>()} |
24 | { |
25 | created(nullptr, nullptr); |
26 | perf_report->name_surface(surface_name.c_str()); |
27 | @@ -119,21 +120,23 @@ |
28 | display_server(server), |
29 | mode(BufferStreamMode::Producer), |
30 | client_platform(client_platform), |
31 | + protobuf_bs{mcl::make_protobuf_object<mir::protobuf::BufferStream>()}, |
32 | buffer_depository{client_platform->create_buffer_factory(), mir::frontend::client_buffer_cache_size}, |
33 | swap_interval_(1), |
34 | - perf_report(perf_report) |
35 | + perf_report(perf_report), |
36 | + protobuf_void{mcl::make_protobuf_object<mir::protobuf::Void>()} |
37 | { |
38 | perf_report->name_surface(std::to_string(reinterpret_cast<long int>(this)).c_str()); |
39 | |
40 | create_wait_handle.expect_result(); |
41 | try |
42 | { |
43 | - server.create_buffer_stream(0, ¶meters, &protobuf_bs, gp::NewCallback(this, &mcl::BufferStream::created, callback, |
44 | + server.create_buffer_stream(0, ¶meters, protobuf_bs.get(), gp::NewCallback(this, &mcl::BufferStream::created, callback, |
45 | context)); |
46 | } |
47 | catch (std::exception const& ex) |
48 | { |
49 | - protobuf_bs.set_error(std::string{"Error invoking create buffer stream: "} + |
50 | + protobuf_bs->set_error(std::string{"Error invoking create buffer stream: "} + |
51 | boost::diagnostic_information(ex)); |
52 | } |
53 | |
54 | @@ -141,16 +144,16 @@ |
55 | |
56 | void mcl::BufferStream::created(mir_buffer_stream_callback callback, void *context) |
57 | { |
58 | - if (!protobuf_bs.has_id() || protobuf_bs.has_error()) |
59 | - BOOST_THROW_EXCEPTION(std::runtime_error("Can not create buffer stream: " + std::string(protobuf_bs.error()))); |
60 | - if (!protobuf_bs.has_buffer()) |
61 | + if (!protobuf_bs->has_id() || protobuf_bs->has_error()) |
62 | + BOOST_THROW_EXCEPTION(std::runtime_error("Can not create buffer stream: " + std::string(protobuf_bs->error()))); |
63 | + if (!protobuf_bs->has_buffer()) |
64 | BOOST_THROW_EXCEPTION(std::runtime_error("Buffer stream did not come with a buffer")); |
65 | |
66 | - process_buffer(protobuf_bs.buffer()); |
67 | + process_buffer(protobuf_bs->buffer()); |
68 | egl_native_window_ = client_platform->create_egl_native_window(this); |
69 | |
70 | if (connection) |
71 | - connection->on_stream_created(protobuf_bs.id().value(), this); |
72 | + connection->on_stream_created(protobuf_bs->id().value(), this); |
73 | |
74 | if (callback) |
75 | callback(reinterpret_cast<MirBufferStream*>(this), context); |
76 | @@ -180,7 +183,7 @@ |
77 | |
78 | try |
79 | { |
80 | - auto pixel_format = static_cast<MirPixelFormat>(protobuf_bs.pixel_format()); |
81 | + auto pixel_format = static_cast<MirPixelFormat>(protobuf_bs->pixel_format()); |
82 | buffer_depository.deposit_package(buffer_package, |
83 | buffer.buffer_id(), |
84 | cached_buffer_size, pixel_format); |
85 | @@ -199,40 +202,37 @@ |
86 | |
87 | secured_region.reset(); |
88 | |
89 | - mir::protobuf::BufferStreamId buffer_stream_id; |
90 | - buffer_stream_id.set_value(protobuf_bs.id().value()); |
91 | - |
92 | -// TODO: We can fix the strange "ID casting" used below in the second phase |
93 | -// of buffer stream which generalizes and clarifies the server side logic. |
94 | + // TODO: We can fix the strange "ID casting" used below in the second phase |
95 | + // of buffer stream which generalizes and clarifies the server side logic. |
96 | if (mode == mcl::BufferStreamMode::Producer) |
97 | { |
98 | - mp::BufferRequest request; |
99 | - request.mutable_id()->set_value(protobuf_bs.id().value()); |
100 | - request.mutable_buffer()->set_buffer_id(protobuf_bs.buffer().buffer_id()); |
101 | + auto request = mcl::make_protobuf_object<mp::BufferRequest>(); |
102 | + request->mutable_id()->set_value(protobuf_bs->id().value()); |
103 | + request->mutable_buffer()->set_buffer_id(protobuf_bs->buffer().buffer_id()); |
104 | |
105 | lock.unlock(); |
106 | next_buffer_wait_handle.expect_result(); |
107 | |
108 | display_server.exchange_buffer( |
109 | nullptr, |
110 | - &request, |
111 | - protobuf_bs.mutable_buffer(), |
112 | + request.get(), |
113 | + protobuf_bs->mutable_buffer(), |
114 | google::protobuf::NewCallback( |
115 | this, &mcl::BufferStream::next_buffer_received, |
116 | done)); |
117 | } |
118 | else |
119 | { |
120 | - mp::ScreencastId screencast_id; |
121 | - screencast_id.set_value(protobuf_bs.id().value()); |
122 | + auto screencast_id = mcl::make_protobuf_object<mp::ScreencastId>(); |
123 | + screencast_id->set_value(protobuf_bs->id().value()); |
124 | |
125 | lock.unlock(); |
126 | next_buffer_wait_handle.expect_result(); |
127 | |
128 | display_server.screencast_buffer( |
129 | nullptr, |
130 | - &screencast_id, |
131 | - protobuf_bs.mutable_buffer(), |
132 | + screencast_id.get(), |
133 | + protobuf_bs->mutable_buffer(), |
134 | google::protobuf::NewCallback( |
135 | this, &mcl::BufferStream::next_buffer_received, |
136 | done)); |
137 | @@ -270,7 +270,7 @@ |
138 | void mcl::BufferStream::next_buffer_received( |
139 | std::function<void()> done) |
140 | { |
141 | - process_buffer(protobuf_bs.buffer()); |
142 | + process_buffer(protobuf_bs->buffer()); |
143 | |
144 | done(); |
145 | |
146 | @@ -285,8 +285,8 @@ |
147 | "", |
148 | cached_buffer_size.width.as_int(), |
149 | cached_buffer_size.height.as_int(), |
150 | - static_cast<MirPixelFormat>(protobuf_bs.pixel_format()), |
151 | - static_cast<MirBufferUsage>(protobuf_bs.buffer_usage()), |
152 | + static_cast<MirPixelFormat>(protobuf_bs->pixel_format()), |
153 | + static_cast<MirBufferUsage>(protobuf_bs->buffer_usage()), |
154 | mir_display_output_id_invalid}; |
155 | } |
156 | |
157 | @@ -318,20 +318,21 @@ |
158 | BOOST_THROW_EXCEPTION(std::logic_error("Attempt to set swap interval on screencast is invalid")); |
159 | } |
160 | |
161 | - mp::SurfaceSetting setting, result; |
162 | - setting.mutable_surfaceid()->set_value(protobuf_bs.id().value()); |
163 | - setting.set_attrib(attrib); |
164 | - setting.set_ivalue(value); |
165 | + auto setting = mcl::make_protobuf_object<mp::SurfaceSetting>(); |
166 | + auto result = mcl::make_protobuf_object<mp::SurfaceSetting>(); |
167 | + setting->mutable_surfaceid()->set_value(protobuf_bs->id().value()); |
168 | + setting->set_attrib(attrib); |
169 | + setting->set_ivalue(value); |
170 | lock.unlock(); |
171 | |
172 | configure_wait_handle.expect_result(); |
173 | - display_server.configure_surface(0, &setting, &result, |
174 | + display_server.configure_surface(0, setting.get(), result.get(), |
175 | google::protobuf::NewCallback(this, &mcl::BufferStream::on_configured)); |
176 | |
177 | configure_wait_handle.wait_for_all(); |
178 | |
179 | lock.lock(); |
180 | - swap_interval_ = result.ivalue(); |
181 | + swap_interval_ = result->ivalue(); |
182 | } |
183 | |
184 | uint32_t mcl::BufferStream::get_current_buffer_id() |
185 | @@ -381,13 +382,13 @@ |
186 | { |
187 | std::unique_lock<decltype(mutex)> lock(mutex); |
188 | |
189 | - return mf::BufferStreamId(protobuf_bs.id().value()); |
190 | + return mf::BufferStreamId(protobuf_bs->id().value()); |
191 | } |
192 | |
193 | bool mcl::BufferStream::valid() const |
194 | { |
195 | std::unique_lock<decltype(mutex)> lock(mutex); |
196 | - return protobuf_bs.has_id() && !protobuf_bs.has_error(); |
197 | + return protobuf_bs->has_id() && !protobuf_bs->has_error(); |
198 | } |
199 | |
200 | void mcl::BufferStream::set_buffer_cache_size(unsigned int cache_size) |
201 | |
202 | === modified file 'src/client/buffer_stream.h' |
203 | --- src/client/buffer_stream.h 2015-06-03 19:17:55 +0000 |
204 | +++ src/client/buffer_stream.h 2015-06-16 23:39:42 +0000 |
205 | @@ -62,7 +62,7 @@ |
206 | mir::protobuf::DisplayServer& server, |
207 | BufferStreamMode mode, |
208 | std::shared_ptr<ClientPlatform> const& native_window_factory, |
209 | - protobuf::BufferStream const& protobuf_bs, |
210 | + mir::protobuf::BufferStream const& protobuf_bs, |
211 | std::shared_ptr<PerfReport> const& perf_report, |
212 | std::string const& surface_name); |
213 | // For surfaceless buffer streams |
214 | @@ -124,7 +124,7 @@ |
215 | BufferStreamMode const mode; |
216 | std::shared_ptr<ClientPlatform> const client_platform; |
217 | |
218 | - mir::protobuf::BufferStream protobuf_bs; |
219 | + std::unique_ptr<mir::protobuf::BufferStream> protobuf_bs; |
220 | mir::client::ClientBufferDepository buffer_depository; |
221 | |
222 | int swap_interval_; |
223 | @@ -137,7 +137,7 @@ |
224 | MirWaitHandle release_wait_handle; |
225 | MirWaitHandle next_buffer_wait_handle; |
226 | MirWaitHandle configure_wait_handle; |
227 | - mir::protobuf::Void protobuf_void; |
228 | + std::unique_ptr<mir::protobuf::Void> protobuf_void; |
229 | |
230 | std::shared_ptr<MemoryRegion> secured_region; |
231 | |
232 | |
233 | === added file 'src/client/make_protobuf_object.h' |
234 | --- src/client/make_protobuf_object.h 1970-01-01 00:00:00 +0000 |
235 | +++ src/client/make_protobuf_object.h 2015-06-16 23:39:42 +0000 |
236 | @@ -0,0 +1,42 @@ |
237 | +/* |
238 | + * Copyright © 2015 Canonical Ltd. |
239 | + * |
240 | + * This program is free software: you can redistribute it and/or modify it |
241 | + * under the terms of the GNU Lesser General Public License version 3, |
242 | + * as published by the Free Software Foundation. |
243 | + * |
244 | + * This program is distributed in the hope that it will be useful, |
245 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
246 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
247 | + * GNU Lesser General Public License for more details. |
248 | + * |
249 | + * You should have received a copy of the GNU Lesser General Public License |
250 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
251 | + * |
252 | + * Authored by: Alberto Aguirre <alberto.aguirre@canonical.com> |
253 | + */ |
254 | + |
255 | +#ifndef MIR_CLIENT_MAKE_PROTOBUF_OBJECT_ |
256 | +#define MIR_CLIENT_MAKE_PROTOBUF_OBJECT_ |
257 | + |
258 | +namespace mir |
259 | +{ |
260 | +namespace client |
261 | +{ |
262 | +template <typename ProtobufType> |
263 | +auto make_protobuf_object() |
264 | +{ |
265 | + return std::unique_ptr<ProtobufType>{ProtobufType::default_instance().New()}; |
266 | +} |
267 | + |
268 | +template <typename ProtobufType> |
269 | +auto make_protobuf_object(ProtobufType const& from) |
270 | +{ |
271 | + auto object = make_protobuf_object<ProtobufType>(); |
272 | + object->CopyFrom(from); |
273 | + return object; |
274 | +} |
275 | +} |
276 | +} |
277 | + |
278 | +#endif |
279 | |
280 | === modified file 'src/client/mir_connection.cpp' |
281 | --- src/client/mir_connection.cpp 2015-06-03 17:01:43 +0000 |
282 | +++ src/client/mir_connection.cpp 2015-06-16 23:39:42 +0000 |
283 | @@ -20,6 +20,7 @@ |
284 | #include "mir_surface.h" |
285 | #include "mir_prompt_session.h" |
286 | #include "default_client_buffer_stream_factory.h" |
287 | +#include "make_protobuf_object.h" |
288 | #include "mir_toolkit/mir_platform_message.h" |
289 | #include "mir/client_platform.h" |
290 | #include "mir/client_platform_factory.h" |
291 | @@ -107,7 +108,13 @@ |
292 | server(channel.get(), ::google::protobuf::Service::STUB_DOESNT_OWN_CHANNEL), |
293 | debug(channel.get(), ::google::protobuf::Service::STUB_DOESNT_OWN_CHANNEL), |
294 | logger(conf.the_logger()), |
295 | + void_response{mcl::make_protobuf_object<mir::protobuf::Void>()}, |
296 | + connect_result{mcl::make_protobuf_object<mir::protobuf::Connection>()}, |
297 | connect_done{false}, |
298 | + ignored{mcl::make_protobuf_object<mir::protobuf::Void>()}, |
299 | + connect_parameters{mcl::make_protobuf_object<mir::protobuf::ConnectParameters>()}, |
300 | + platform_operation_reply{mcl::make_protobuf_object<mir::protobuf::PlatformOperationMessage>()}, |
301 | + display_configuration_response{mcl::make_protobuf_object<mir::protobuf::DisplayConfiguration>()}, |
302 | client_platform_factory(conf.the_client_platform_factory()), |
303 | input_platform(conf.the_input_platform()), |
304 | display_configuration(conf.the_display_configuration()), |
305 | @@ -116,7 +123,7 @@ |
306 | event_handler_register(conf.the_event_handler_register()), |
307 | eventloop{new md::ThreadedDispatcher{"RPC Thread", std::dynamic_pointer_cast<md::Dispatchable>(channel)}} |
308 | { |
309 | - connect_result.set_error("connect not called"); |
310 | + connect_result->set_error("connect not called"); |
311 | { |
312 | std::lock_guard<std::mutex> lock(connection_guard); |
313 | next_valid = valid_connections; |
314 | @@ -131,9 +138,9 @@ |
315 | connect_wait_handle.wait_for_pending(std::chrono::milliseconds(500)); |
316 | |
317 | std::lock_guard<decltype(mutex)> lock(mutex); |
318 | - if (connect_result.has_platform()) |
319 | + if (connect_result && connect_result->has_platform()) |
320 | { |
321 | - auto const& platform = connect_result.platform(); |
322 | + auto const& platform = connect_result->platform(); |
323 | for (int i = 0, end = platform.fd_size(); i != end; ++i) |
324 | close(platform.fd(i)); |
325 | } |
326 | @@ -154,9 +161,9 @@ |
327 | { |
328 | std::lock_guard<decltype(mutex)> lock(mutex); |
329 | |
330 | - if (connect_result.has_error()) |
331 | + if (connect_result && connect_result->has_error()) |
332 | { |
333 | - return connect_result.error().c_str(); |
334 | + return connect_result->error().c_str(); |
335 | } |
336 | |
337 | return error_message.c_str(); |
338 | @@ -220,8 +227,8 @@ |
339 | |
340 | SurfaceRelease surf_release{surface, new_wait_handle, callback, context}; |
341 | |
342 | - mir::protobuf::SurfaceId message; |
343 | - message.set_value(surface->id()); |
344 | + auto message = mcl::make_protobuf_object<mir::protobuf::SurfaceId>(); |
345 | + message->set_value(surface->id()); |
346 | |
347 | { |
348 | std::lock_guard<decltype(release_wait_handle_guard)> rel_lock(release_wait_handle_guard); |
349 | @@ -229,7 +236,7 @@ |
350 | } |
351 | |
352 | new_wait_handle->expect_result(); |
353 | - server.release_surface(0, &message, &void_response, |
354 | + server.release_surface(0, message.get(), void_response.get(), |
355 | gp::NewCallback(this, &MirConnection::released, surf_release)); |
356 | |
357 | |
358 | @@ -248,9 +255,9 @@ |
359 | { |
360 | std::lock_guard<decltype(mutex)> lock(mutex); |
361 | |
362 | - if (!connect_result.has_platform() || !connect_result.has_display_configuration()) |
363 | + if (!connect_result->has_platform() || !connect_result->has_display_configuration()) |
364 | { |
365 | - if (!connect_result.has_error()) |
366 | + if (!connect_result->has_error()) |
367 | { |
368 | // We're handling an error scenario that means we're not sync'd |
369 | // with the client code - a callback isn't safe (or needed) |
370 | @@ -283,12 +290,12 @@ |
371 | buffer_stream_factory = std::make_shared<mcl::DefaultClientBufferStreamFactory>( |
372 | platform, the_logger()); |
373 | native_display = platform->create_egl_native_display(); |
374 | - display_configuration->set_configuration(connect_result.display_configuration()); |
375 | + display_configuration->set_configuration(connect_result->display_configuration()); |
376 | lifecycle_control->set_lifecycle_event_handler(default_lifecycle_event_handler); |
377 | } |
378 | catch (std::exception const& e) |
379 | { |
380 | - connect_result.set_error(std::string{"Failed to process connect response: "} + |
381 | + connect_result->set_error(std::string{"Failed to process connect response: "} + |
382 | boost::diagnostic_information(e)); |
383 | } |
384 | |
385 | @@ -304,14 +311,14 @@ |
386 | { |
387 | std::lock_guard<decltype(mutex)> lock(mutex); |
388 | |
389 | - connect_parameters.set_application_name(app_name); |
390 | + connect_parameters->set_application_name(app_name); |
391 | connect_wait_handle.expect_result(); |
392 | } |
393 | |
394 | server.connect( |
395 | 0, |
396 | - &connect_parameters, |
397 | - &connect_result, |
398 | + connect_parameters.get(), |
399 | + connect_result.get(), |
400 | google::protobuf::NewCallback( |
401 | this, &MirConnection::connected, callback, context)); |
402 | return &connect_wait_handle; |
403 | @@ -339,7 +346,7 @@ |
404 | disconnecting = true; |
405 | } |
406 | disconnect_wait_handle.expect_result(); |
407 | - server.disconnect(0, &ignored, &ignored, |
408 | + server.disconnect(0, ignored.get(), ignored.get(), |
409 | google::protobuf::NewCallback(this, &MirConnection::done_disconnect)); |
410 | |
411 | return &disconnect_wait_handle; |
412 | @@ -348,19 +355,19 @@ |
413 | void MirConnection::done_platform_operation( |
414 | mir_platform_operation_callback callback, void* context) |
415 | { |
416 | - auto reply = mir_platform_message_create(platform_operation_reply.opcode()); |
417 | + auto reply = mir_platform_message_create(platform_operation_reply->opcode()); |
418 | |
419 | - set_error_message(platform_operation_reply.error()); |
420 | + set_error_message(platform_operation_reply->error()); |
421 | |
422 | mir_platform_message_set_data( |
423 | reply, |
424 | - platform_operation_reply.data().data(), |
425 | - platform_operation_reply.data().size()); |
426 | + platform_operation_reply->data().data(), |
427 | + platform_operation_reply->data().size()); |
428 | |
429 | mir_platform_message_set_fds( |
430 | reply, |
431 | - platform_operation_reply.fd().data(), |
432 | - platform_operation_reply.fd().size()); |
433 | + platform_operation_reply->fd().data(), |
434 | + platform_operation_reply->fd().size()); |
435 | |
436 | callback(this, reply, context); |
437 | |
438 | @@ -379,21 +386,21 @@ |
439 | return nullptr; |
440 | } |
441 | |
442 | - mir::protobuf::PlatformOperationMessage protobuf_request; |
443 | + auto protobuf_request = mcl::make_protobuf_object<mir::protobuf::PlatformOperationMessage>(); |
444 | |
445 | - protobuf_request.set_opcode(mir_platform_message_get_opcode(request)); |
446 | + protobuf_request->set_opcode(mir_platform_message_get_opcode(request)); |
447 | auto const request_data = mir_platform_message_get_data(request); |
448 | auto const request_fds = mir_platform_message_get_fds(request); |
449 | |
450 | - protobuf_request.set_data(request_data.data, request_data.size); |
451 | + protobuf_request->set_data(request_data.data, request_data.size); |
452 | for (size_t i = 0; i != request_fds.num_fds; ++i) |
453 | - protobuf_request.add_fd(request_fds.fds[i]); |
454 | + protobuf_request->add_fd(request_fds.fds[i]); |
455 | |
456 | platform_operation_wait_handle.expect_result(); |
457 | server.platform_operation( |
458 | 0, |
459 | - &protobuf_request, |
460 | - &platform_operation_reply, |
461 | + protobuf_request.get(), |
462 | + platform_operation_reply.get(), |
463 | google::protobuf::NewCallback(this, &MirConnection::done_platform_operation, |
464 | callback, context)); |
465 | |
466 | @@ -411,7 +418,7 @@ |
467 | { |
468 | lock.unlock(); |
469 | std::lock_guard<decltype(connection->mutex)> lock(connection->mutex); |
470 | - return !connection->connect_result.has_error(); |
471 | + return !connection->connect_result->has_error(); |
472 | } |
473 | } |
474 | } |
475 | @@ -427,9 +434,9 @@ |
476 | { |
477 | // connect_result is write-once: once it's valid, we don't need to lock |
478 | // to use it. |
479 | - if (connect_done && !connect_result.has_error() && connect_result.has_platform()) |
480 | + if (connect_done && !connect_result->has_error() && connect_result->has_platform()) |
481 | { |
482 | - auto const& platform = connect_result.platform(); |
483 | + auto const& platform = connect_result->platform(); |
484 | |
485 | platform_package.data_items = platform.data_size(); |
486 | for (int i = 0; i != platform.data_size(); ++i) |
487 | @@ -460,15 +467,15 @@ |
488 | valid_formats = 0; |
489 | |
490 | std::lock_guard<decltype(mutex)> lock(mutex); |
491 | - if (!connect_result.has_error()) |
492 | + if (!connect_result->has_error()) |
493 | { |
494 | valid_formats = std::min( |
495 | - static_cast<unsigned int>(connect_result.surface_pixel_format_size()), |
496 | + static_cast<unsigned int>(connect_result->surface_pixel_format_size()), |
497 | formats_size); |
498 | |
499 | for (auto i = 0u; i < valid_formats; i++) |
500 | { |
501 | - formats[i] = static_cast<MirPixelFormat>(connect_result.surface_pixel_format(i)); |
502 | + formats[i] = static_cast<MirPixelFormat>(connect_result->surface_pixel_format(i)); |
503 | } |
504 | } |
505 | } |
506 | @@ -488,13 +495,13 @@ |
507 | mir_buffer_stream_callback callback, |
508 | void *context) |
509 | { |
510 | - mir::protobuf::BufferStreamParameters params; |
511 | - params.set_width(width); |
512 | - params.set_height(height); |
513 | - params.set_pixel_format(format); |
514 | - params.set_buffer_usage(buffer_usage); |
515 | + auto params = mcl::make_protobuf_object<mir::protobuf::BufferStreamParameters>(); |
516 | + params->set_width(width); |
517 | + params->set_height(height); |
518 | + params->set_pixel_format(format); |
519 | + params->set_buffer_usage(buffer_usage); |
520 | |
521 | - return buffer_stream_factory->make_producer_stream(this, server, params, callback, context); |
522 | + return buffer_stream_factory->make_producer_stream(this, server, *params, callback, context); |
523 | } |
524 | |
525 | std::shared_ptr<mir::client::ClientBufferStream> MirConnection::make_consumer_stream( |
526 | @@ -559,10 +566,10 @@ |
527 | { |
528 | std::lock_guard<decltype(mutex)> lock(mutex); |
529 | |
530 | - set_error_message(display_configuration_response.error()); |
531 | + set_error_message(display_configuration_response->error()); |
532 | |
533 | - if (!display_configuration_response.has_error()) |
534 | - display_configuration->set_configuration(display_configuration_response); |
535 | + if (!display_configuration_response->has_error()) |
536 | + display_configuration->set_configuration(*display_configuration_response); |
537 | |
538 | return configure_display_wait_handle.result_received(); |
539 | } |
540 | @@ -574,14 +581,14 @@ |
541 | return NULL; |
542 | } |
543 | |
544 | - mir::protobuf::DisplayConfiguration request; |
545 | + auto request = mcl::make_protobuf_object<mir::protobuf::DisplayConfiguration>(); |
546 | { |
547 | std::lock_guard<decltype(mutex)> lock(mutex); |
548 | |
549 | for (auto i=0u; i < config->num_outputs; i++) |
550 | { |
551 | auto output = config->outputs[i]; |
552 | - auto display_request = request.add_display_output(); |
553 | + auto display_request = request->add_display_output(); |
554 | display_request->set_output_id(output.output_id); |
555 | display_request->set_used(output.used); |
556 | display_request->set_current_mode(output.current_mode); |
557 | @@ -594,7 +601,7 @@ |
558 | } |
559 | |
560 | configure_display_wait_handle.expect_result(); |
561 | - server.configure_display(0, &request, &display_configuration_response, |
562 | + server.configure_display(0, request.get(), display_configuration_response.get(), |
563 | google::protobuf::NewCallback(this, &MirConnection::done_display_configure)); |
564 | |
565 | return &configure_display_wait_handle; |
566 | @@ -619,8 +626,8 @@ |
567 | |
568 | StreamRelease stream_release{stream, new_wait_handle, callback, context}; |
569 | |
570 | - mir::protobuf::BufferStreamId buffer_stream_id; |
571 | - buffer_stream_id.set_value(stream->rpc_id().as_value()); |
572 | + auto buffer_stream_id = mcl::make_protobuf_object<mir::protobuf::BufferStreamId>(); |
573 | + buffer_stream_id->set_value(stream->rpc_id().as_value()); |
574 | |
575 | { |
576 | std::lock_guard<decltype(release_wait_handle_guard)> rel_lock(release_wait_handle_guard); |
577 | @@ -629,7 +636,7 @@ |
578 | |
579 | new_wait_handle->expect_result(); |
580 | server.release_buffer_stream( |
581 | - nullptr, &buffer_stream_id, &void_response, |
582 | + nullptr, buffer_stream_id.get(), void_response.get(), |
583 | google::protobuf::NewCallback(this, &MirConnection::released, stream_release)); |
584 | return new_wait_handle; |
585 | } |
586 | |
587 | === modified file 'src/client/mir_connection.h' |
588 | --- src/client/mir_connection.h 2015-06-03 17:01:43 +0000 |
589 | +++ src/client/mir_connection.h 2015-06-16 23:39:42 +0000 |
590 | @@ -35,6 +35,8 @@ |
591 | |
592 | #include "mir_wait_handle.h" |
593 | |
594 | +#include <memory> |
595 | + |
596 | namespace mir |
597 | { |
598 | class SharedLibrary; |
599 | @@ -172,13 +174,13 @@ |
600 | mir::protobuf::DisplayServer::Stub server; |
601 | mir::protobuf::Debug::Stub debug; |
602 | std::shared_ptr<mir::logging::Logger> const logger; |
603 | - mir::protobuf::Void void_response; |
604 | - mir::protobuf::Connection connect_result; |
605 | + std::unique_ptr<mir::protobuf::Void> void_response; |
606 | + std::unique_ptr<mir::protobuf::Connection> connect_result; |
607 | std::atomic<bool> connect_done; |
608 | - mir::protobuf::Void ignored; |
609 | - mir::protobuf::ConnectParameters connect_parameters; |
610 | - mir::protobuf::PlatformOperationMessage platform_operation_reply; |
611 | - mir::protobuf::DisplayConfiguration display_configuration_response; |
612 | + std::unique_ptr<mir::protobuf::Void> ignored; |
613 | + std::unique_ptr<mir::protobuf::ConnectParameters> connect_parameters; |
614 | + std::unique_ptr<mir::protobuf::PlatformOperationMessage> platform_operation_reply; |
615 | + std::unique_ptr<mir::protobuf::DisplayConfiguration> display_configuration_response; |
616 | std::atomic<bool> disconnecting{false}; |
617 | |
618 | std::shared_ptr<mir::client::ClientPlatformFactory> const client_platform_factory; |
619 | |
620 | === modified file 'src/client/mir_prompt_session.cpp' |
621 | --- src/client/mir_prompt_session.cpp 2015-03-31 02:35:42 +0000 |
622 | +++ src/client/mir_prompt_session.cpp 2015-06-16 23:39:42 +0000 |
623 | @@ -18,6 +18,7 @@ |
624 | |
625 | #include "mir_prompt_session.h" |
626 | #include "event_handler_register.h" |
627 | +#include "make_protobuf_object.h" |
628 | |
629 | namespace mp = mir::protobuf; |
630 | namespace mcl = mir::client; |
631 | @@ -26,6 +27,10 @@ |
632 | mp::DisplayServer& server, |
633 | std::shared_ptr<mcl::EventHandlerRegister> const& event_handler_register) : |
634 | server(server), |
635 | + parameters(mcl::make_protobuf_object<mir::protobuf::PromptSessionParameters>()), |
636 | + add_result(mcl::make_protobuf_object<mir::protobuf::Void>()), |
637 | + protobuf_void(mcl::make_protobuf_object<mir::protobuf::Void>()), |
638 | + socket_fd_response(mcl::make_protobuf_object<mir::protobuf::SocketFD>()), |
639 | event_handler_register(event_handler_register), |
640 | event_handler_register_id{event_handler_register->register_event_handler( |
641 | [this](MirEvent const& event) |
642 | @@ -34,6 +39,7 @@ |
643 | set_state(mir_prompt_session_event_get_state(mir_event_get_prompt_session_event(&event))); |
644 | })}, |
645 | state(mir_prompt_session_state_stopped), |
646 | + session(mcl::make_protobuf_object<mir::protobuf::Void>()), |
647 | handle_prompt_session_state_change{[](MirPromptSessionState){}} |
648 | { |
649 | } |
650 | @@ -64,14 +70,14 @@ |
651 | { |
652 | { |
653 | std::lock_guard<decltype(mutex)> lock(mutex); |
654 | - parameters.set_application_pid(application_pid); |
655 | + parameters->set_application_pid(application_pid); |
656 | } |
657 | |
658 | start_wait_handle.expect_result(); |
659 | server.start_prompt_session( |
660 | 0, |
661 | - ¶meters, |
662 | - &session, |
663 | + parameters.get(), |
664 | + session.get(), |
665 | google::protobuf::NewCallback(this, &MirPromptSession::done_start, |
666 | callback, context)); |
667 | |
668 | @@ -84,8 +90,8 @@ |
669 | |
670 | server.stop_prompt_session( |
671 | 0, |
672 | - &protobuf_void, |
673 | - &protobuf_void, |
674 | + protobuf_void.get(), |
675 | + protobuf_void.get(), |
676 | google::protobuf::NewCallback(this, &MirPromptSession::done_stop, |
677 | callback, context)); |
678 | |
679 | @@ -110,7 +116,7 @@ |
680 | { |
681 | std::lock_guard<decltype(session_mutex)> lock(session_mutex); |
682 | |
683 | - state = session.has_error() ? mir_prompt_session_state_stopped : mir_prompt_session_state_started; |
684 | + state = session->has_error() ? mir_prompt_session_state_stopped : mir_prompt_session_state_started; |
685 | } |
686 | |
687 | callback(this, context); |
688 | @@ -129,10 +135,10 @@ |
689 | { |
690 | std::lock_guard<decltype(session_mutex)> lock(session_mutex); |
691 | |
692 | - if (!session.has_error()) |
693 | - session.set_error(std::string{}); |
694 | + if (!session->has_error()) |
695 | + session->set_error(std::string{}); |
696 | |
697 | - return session.error().c_str(); |
698 | + return session->error().c_str(); |
699 | } |
700 | |
701 | MirWaitHandle* MirPromptSession::new_fds_for_prompt_providers( |
702 | @@ -140,15 +146,15 @@ |
703 | mir_client_fd_callback callback, |
704 | void * context) |
705 | { |
706 | - mir::protobuf::SocketFDRequest request; |
707 | - request.set_number(no_of_fds); |
708 | + auto request = mcl::make_protobuf_object<mir::protobuf::SocketFDRequest>(); |
709 | + request->set_number(no_of_fds); |
710 | |
711 | fds_for_prompt_providers_wait_handle.expect_result(); |
712 | |
713 | server.new_fds_for_prompt_providers( |
714 | nullptr, |
715 | - &request, |
716 | - &socket_fd_response, |
717 | + request.get(), |
718 | + socket_fd_response.get(), |
719 | google::protobuf::NewCallback(this, &MirPromptSession::done_fds_for_prompt_providers, |
720 | callback, context)); |
721 | |
722 | @@ -159,13 +165,13 @@ |
723 | mir_client_fd_callback callback, |
724 | void* context) |
725 | { |
726 | - auto const size = socket_fd_response.fd_size(); |
727 | + auto const size = socket_fd_response->fd_size(); |
728 | |
729 | std::vector<int> fds; |
730 | fds.reserve(size); |
731 | |
732 | for (auto i = 0; i != size; ++i) |
733 | - fds.push_back(socket_fd_response.fd(i)); |
734 | + fds.push_back(socket_fd_response->fd(i)); |
735 | |
736 | callback(this, size, fds.data(), context); |
737 | fds_for_prompt_providers_wait_handle.result_received(); |
738 | |
739 | === modified file 'src/client/mir_prompt_session.h' |
740 | --- src/client/mir_prompt_session.h 2015-01-21 07:34:50 +0000 |
741 | +++ src/client/mir_prompt_session.h 2015-06-16 23:39:42 +0000 |
742 | @@ -60,10 +60,10 @@ |
743 | private: |
744 | std::mutex mutable mutex; // Protects parameters, wait_handles & results |
745 | mir::protobuf::DisplayServer& server; |
746 | - mir::protobuf::PromptSessionParameters parameters; |
747 | - mir::protobuf::Void add_result; |
748 | - mir::protobuf::Void protobuf_void; |
749 | - mir::protobuf::SocketFD socket_fd_response; |
750 | + std::unique_ptr<mir::protobuf::PromptSessionParameters> parameters; |
751 | + std::unique_ptr<mir::protobuf::Void> add_result; |
752 | + std::unique_ptr<mir::protobuf::Void> protobuf_void; |
753 | + std::unique_ptr<mir::protobuf::SocketFD> socket_fd_response; |
754 | std::shared_ptr<mir::client::EventHandlerRegister> const event_handler_register; |
755 | int const event_handler_register_id; |
756 | |
757 | @@ -73,7 +73,7 @@ |
758 | std::atomic<MirPromptSessionState> state; |
759 | |
760 | std::mutex mutable session_mutex; // Protects session |
761 | - mir::protobuf::Void session; |
762 | + std::unique_ptr<mir::protobuf::Void> session; |
763 | |
764 | std::mutex mutable event_handler_mutex; // Need another mutex for callback access to members |
765 | std::function<void(MirPromptSessionState)> handle_prompt_session_state_change; |
766 | |
767 | === modified file 'src/client/mir_screencast.cpp' |
768 | --- src/client/mir_screencast.cpp 2015-06-03 17:35:29 +0000 |
769 | +++ src/client/mir_screencast.cpp 2015-06-16 23:39:42 +0000 |
770 | @@ -18,6 +18,7 @@ |
771 | |
772 | #include "mir_screencast.h" |
773 | #include "mir_connection.h" |
774 | +#include "make_protobuf_object.h" |
775 | #include "client_buffer_stream.h" |
776 | #include "mir/frontend/client_constants.h" |
777 | #include "mir_toolkit/mir_native_buffer.h" |
778 | @@ -38,7 +39,9 @@ |
779 | mir_screencast_callback callback, void* context) |
780 | : server(server), |
781 | connection{connection}, |
782 | - output_size{size} |
783 | + output_size{size}, |
784 | + protobuf_screencast{mcl::make_protobuf_object<mir::protobuf::Screencast>()}, |
785 | + protobuf_void{mcl::make_protobuf_object<mir::protobuf::Void>()} |
786 | { |
787 | if (output_size.width.as_int() == 0 || |
788 | output_size.height.as_int() == 0 || |
789 | @@ -48,23 +51,23 @@ |
790 | { |
791 | BOOST_THROW_EXCEPTION(std::runtime_error("Invalid parameters")); |
792 | } |
793 | - protobuf_screencast.set_error("Not initialized"); |
794 | - |
795 | - mir::protobuf::ScreencastParameters parameters; |
796 | - |
797 | - parameters.mutable_region()->set_left(region.top_left.x.as_int()); |
798 | - parameters.mutable_region()->set_top(region.top_left.y.as_int()); |
799 | - parameters.mutable_region()->set_width(region.size.width.as_uint32_t()); |
800 | - parameters.mutable_region()->set_height(region.size.height.as_uint32_t()); |
801 | - parameters.set_width(output_size.width.as_uint32_t()); |
802 | - parameters.set_height(output_size.height.as_uint32_t()); |
803 | - parameters.set_pixel_format(pixel_format); |
804 | + protobuf_screencast->set_error("Not initialized"); |
805 | + |
806 | + auto parameters = mcl::make_protobuf_object<mir::protobuf::ScreencastParameters>(); |
807 | + |
808 | + parameters->mutable_region()->set_left(region.top_left.x.as_int()); |
809 | + parameters->mutable_region()->set_top(region.top_left.y.as_int()); |
810 | + parameters->mutable_region()->set_width(region.size.width.as_uint32_t()); |
811 | + parameters->mutable_region()->set_height(region.size.height.as_uint32_t()); |
812 | + parameters->set_width(output_size.width.as_uint32_t()); |
813 | + parameters->set_height(output_size.height.as_uint32_t()); |
814 | + parameters->set_pixel_format(pixel_format); |
815 | |
816 | create_screencast_wait_handle.expect_result(); |
817 | server.create_screencast( |
818 | nullptr, |
819 | - ¶meters, |
820 | - &protobuf_screencast, |
821 | + parameters.get(), |
822 | + protobuf_screencast.get(), |
823 | google::protobuf::NewCallback( |
824 | this, &MirScreencast::screencast_created, |
825 | callback, context)); |
826 | @@ -77,20 +80,20 @@ |
827 | |
828 | bool MirScreencast::valid() |
829 | { |
830 | - return !protobuf_screencast.has_error(); |
831 | + return !protobuf_screencast->has_error(); |
832 | } |
833 | |
834 | MirWaitHandle* MirScreencast::release( |
835 | mir_screencast_callback callback, void* context) |
836 | { |
837 | - mir::protobuf::ScreencastId screencast_id; |
838 | - screencast_id.set_value(protobuf_screencast.screencast_id().value()); |
839 | + auto screencast_id = mcl::make_protobuf_object<mir::protobuf::ScreencastId>(); |
840 | + screencast_id->set_value(protobuf_screencast->screencast_id().value()); |
841 | |
842 | release_wait_handle.expect_result(); |
843 | server.release_screencast( |
844 | nullptr, |
845 | - &screencast_id, |
846 | - &protobuf_void, |
847 | + screencast_id.get(), |
848 | + protobuf_void.get(), |
849 | google::protobuf::NewCallback( |
850 | this, &MirScreencast::released, callback, context)); |
851 | |
852 | @@ -104,10 +107,10 @@ |
853 | void MirScreencast::screencast_created( |
854 | mir_screencast_callback callback, void* context) |
855 | { |
856 | - if (!protobuf_screencast.has_error() && connection) |
857 | + if (!protobuf_screencast->has_error() && connection) |
858 | { |
859 | buffer_stream = connection->make_consumer_stream( |
860 | - protobuf_screencast.buffer_stream(), "MirScreencast"); |
861 | + protobuf_screencast->buffer_stream(), "MirScreencast"); |
862 | } |
863 | |
864 | callback(this, context); |
865 | |
866 | === modified file 'src/client/mir_screencast.h' |
867 | --- src/client/mir_screencast.h 2015-06-03 17:35:29 +0000 |
868 | +++ src/client/mir_screencast.h 2015-06-16 23:39:42 +0000 |
869 | @@ -27,6 +27,8 @@ |
870 | |
871 | #include <EGL/eglplatform.h> |
872 | |
873 | +#include <memory> |
874 | + |
875 | namespace mir |
876 | { |
877 | namespace protobuf { class DisplayServer; } |
878 | @@ -71,8 +73,8 @@ |
879 | mir::geometry::Size const output_size; |
880 | std::shared_ptr<mir::client::ClientBufferStream> buffer_stream; |
881 | |
882 | - mir::protobuf::Screencast protobuf_screencast; |
883 | - mir::protobuf::Void protobuf_void; |
884 | + std::unique_ptr<mir::protobuf::Screencast> protobuf_screencast; |
885 | + std::unique_ptr<mir::protobuf::Void> protobuf_void; |
886 | |
887 | MirWaitHandle create_screencast_wait_handle; |
888 | MirWaitHandle release_wait_handle; |
889 | |
890 | === modified file 'src/client/mir_surface.cpp' |
891 | --- src/client/mir_surface.cpp 2015-06-16 12:18:54 +0000 |
892 | +++ src/client/mir_surface.cpp 2015-06-16 23:39:42 +0000 |
893 | @@ -16,12 +16,13 @@ |
894 | * Authored by: Thomas Guest <thomas.guest@canonical.com> |
895 | */ |
896 | |
897 | +#include "mir_surface.h" |
898 | +#include "cursor_configuration.h" |
899 | +#include "client_buffer_stream_factory.h" |
900 | +#include "make_protobuf_object.h" |
901 | #include "mir_toolkit/mir_client_library.h" |
902 | #include "mir/frontend/client_constants.h" |
903 | #include "mir/client_buffer.h" |
904 | -#include "mir_surface.h" |
905 | -#include "cursor_configuration.h" |
906 | -#include "client_buffer_stream_factory.h" |
907 | #include "mir_connection.h" |
908 | #include "client_buffer_stream.h" |
909 | #include "mir/dispatch/threaded_dispatcher.h" |
910 | @@ -42,7 +43,7 @@ |
911 | |
912 | #define SERIALIZE_OPTION_IF_SET(option, message) \ |
913 | if (option.is_set()) \ |
914 | - message.set_##option(option.value()); |
915 | + message->set_##option(option.value()); |
916 | |
917 | namespace |
918 | { |
919 | @@ -79,9 +80,10 @@ |
920 | { |
921 | } |
922 | |
923 | -mir::protobuf::SurfaceParameters MirSurfaceSpec::serialize() const |
924 | +std::unique_ptr<mir::protobuf::SurfaceParameters> MirSurfaceSpec::serialize() const |
925 | { |
926 | - mir::protobuf::SurfaceParameters message; |
927 | + //std::unique_ptr<mp::SurfaceParameters> message{mp::SurfaceParameters::default_instance().New()}; |
928 | + auto message = mcl::make_protobuf_object<mp::SurfaceParameters>(); |
929 | |
930 | SERIALIZE_OPTION_IF_SET(width, message); |
931 | SERIALIZE_OPTION_IF_SET(height, message); |
932 | @@ -103,26 +105,26 @@ |
933 | // max_aspect is a special case (below) |
934 | |
935 | if (parent.is_set() && parent.value() != nullptr) |
936 | - message.set_parent_id(parent.value()->id()); |
937 | + message->set_parent_id(parent.value()->id()); |
938 | |
939 | if (aux_rect.is_set()) |
940 | { |
941 | - message.mutable_aux_rect()->set_left(aux_rect.value().left); |
942 | - message.mutable_aux_rect()->set_top(aux_rect.value().top); |
943 | - message.mutable_aux_rect()->set_width(aux_rect.value().width); |
944 | - message.mutable_aux_rect()->set_height(aux_rect.value().height); |
945 | + message->mutable_aux_rect()->set_left(aux_rect.value().left); |
946 | + message->mutable_aux_rect()->set_top(aux_rect.value().top); |
947 | + message->mutable_aux_rect()->set_width(aux_rect.value().width); |
948 | + message->mutable_aux_rect()->set_height(aux_rect.value().height); |
949 | } |
950 | |
951 | if (min_aspect.is_set()) |
952 | { |
953 | - message.mutable_min_aspect()->set_width(min_aspect.value().width); |
954 | - message.mutable_min_aspect()->set_height(min_aspect.value().height); |
955 | + message->mutable_min_aspect()->set_width(min_aspect.value().width); |
956 | + message->mutable_min_aspect()->set_height(min_aspect.value().height); |
957 | } |
958 | |
959 | if (max_aspect.is_set()) |
960 | { |
961 | - message.mutable_max_aspect()->set_width(max_aspect.value().width); |
962 | - message.mutable_max_aspect()->set_height(max_aspect.value().height); |
963 | + message->mutable_max_aspect()->set_width(max_aspect.value().width); |
964 | + message->mutable_max_aspect()->set_height(max_aspect.value().height); |
965 | } |
966 | |
967 | return message; |
968 | @@ -139,8 +141,9 @@ |
969 | } |
970 | |
971 | MirSurface::MirSurface(std::string const& error) |
972 | + : surface{mcl::make_protobuf_object<mir::protobuf::Surface>()} |
973 | { |
974 | - surface.set_error(error); |
975 | + surface->set_error(error); |
976 | |
977 | std::lock_guard<decltype(handle_mutex)> lock(handle_mutex); |
978 | valid_surfaces.insert(this); |
979 | @@ -156,11 +159,16 @@ |
980 | mir_surface_callback callback, void * context) |
981 | : server{&the_server}, |
982 | debug{debug}, |
983 | + surface{mcl::make_protobuf_object<mir::protobuf::Surface>()}, |
984 | + persistent_id{mcl::make_protobuf_object<mir::protobuf::PersistentSurfaceId>()}, |
985 | name{spec.surface_name.is_set() ? spec.surface_name.value() : ""}, |
986 | + void_response{mcl::make_protobuf_object<mir::protobuf::Void>()}, |
987 | + modify_result{mcl::make_protobuf_object<mir::protobuf::Void>()}, |
988 | connection(allocating_connection), |
989 | buffer_stream_factory(buffer_stream_factory), |
990 | input_platform(input_platform), |
991 | - keymapper(std::make_shared<mircv::XKBMapper>()) |
992 | + keymapper(std::make_shared<mircv::XKBMapper>()), |
993 | + configure_result{mcl::make_protobuf_object<mir::protobuf::SurfaceSetting>()} |
994 | { |
995 | for (int i = 0; i < mir_surface_attribs; i++) |
996 | attrib_cache[i] = -1; |
997 | @@ -169,11 +177,11 @@ |
998 | create_wait_handle.expect_result(); |
999 | try |
1000 | { |
1001 | - server->create_surface(0, &message, &surface, gp::NewCallback(this, &MirSurface::created, callback, context)); |
1002 | + server->create_surface(0, message.get(), surface.get(), gp::NewCallback(this, &MirSurface::created, callback, context)); |
1003 | } |
1004 | catch (std::exception const& ex) |
1005 | { |
1006 | - surface.set_error(std::string{"Error invoking create surface: "} + |
1007 | + surface->set_error(std::string{"Error invoking create surface: "} + |
1008 | boost::diagnostic_information(ex)); |
1009 | } |
1010 | |
1011 | @@ -192,8 +200,8 @@ |
1012 | |
1013 | input_thread.reset(); |
1014 | |
1015 | - for (auto i = 0, end = surface.fd_size(); i != end; ++i) |
1016 | - close(surface.fd(i)); |
1017 | + for (auto i = 0, end = surface->fd_size(); i != end; ++i) |
1018 | + close(surface->fd(i)); |
1019 | } |
1020 | |
1021 | MirSurfaceParameters MirSurface::get_parameters() const |
1022 | @@ -207,9 +215,9 @@ |
1023 | { |
1024 | std::lock_guard<decltype(mutex)> lock(mutex); |
1025 | |
1026 | - if (surface.has_error()) |
1027 | + if (surface->has_error()) |
1028 | { |
1029 | - return surface.error().c_str(); |
1030 | + return surface->error().c_str(); |
1031 | } |
1032 | return error_message.c_str(); |
1033 | } |
1034 | @@ -218,7 +226,7 @@ |
1035 | { |
1036 | std::lock_guard<decltype(mutex)> lock(mutex); |
1037 | |
1038 | - return surface.id().value(); |
1039 | + return surface->id().value(); |
1040 | } |
1041 | |
1042 | bool MirSurface::is_valid(MirSurface* query) |
1043 | @@ -226,16 +234,16 @@ |
1044 | std::lock_guard<decltype(handle_mutex)> lock(handle_mutex); |
1045 | |
1046 | if (valid_surfaces.count(query)) |
1047 | - return !query->surface.has_error(); |
1048 | + return !query->surface->has_error(); |
1049 | |
1050 | return false; |
1051 | } |
1052 | |
1053 | void MirSurface::acquired_persistent_id(mir_surface_id_callback callback, void* context) |
1054 | { |
1055 | - if (!persistent_id.has_error()) |
1056 | + if (!persistent_id->has_error()) |
1057 | { |
1058 | - callback(this, new MirPersistentId{persistent_id.value()}, context); |
1059 | + callback(this, new MirPersistentId{persistent_id->value()}, context); |
1060 | } |
1061 | else |
1062 | { |
1063 | @@ -248,20 +256,20 @@ |
1064 | { |
1065 | std::lock_guard<decltype(mutex)> lock{mutex}; |
1066 | |
1067 | - if (persistent_id.has_value()) |
1068 | + if (persistent_id->has_value()) |
1069 | { |
1070 | - callback(this, new MirPersistentId{persistent_id.value()}, context); |
1071 | + callback(this, new MirPersistentId{persistent_id->value()}, context); |
1072 | return nullptr; |
1073 | } |
1074 | |
1075 | persistent_id_wait_handle.expect_result(); |
1076 | try |
1077 | { |
1078 | - server->request_persistent_surface_id(0, &surface.id(), &persistent_id, gp::NewCallback(this, &MirSurface::acquired_persistent_id, callback, context)); |
1079 | + server->request_persistent_surface_id(0, &surface->id(), persistent_id.get(), gp::NewCallback(this, &MirSurface::acquired_persistent_id, callback, context)); |
1080 | } |
1081 | catch (std::exception const& ex) |
1082 | { |
1083 | - surface.set_error(std::string{"Failed to acquire a persistent ID from the server: "} + |
1084 | + surface->set_error(std::string{"Failed to acquire a persistent ID from the server: "} + |
1085 | boost::diagnostic_information(ex)); |
1086 | } |
1087 | return &persistent_id_wait_handle; |
1088 | @@ -283,10 +291,10 @@ |
1089 | { |
1090 | { |
1091 | std::lock_guard<decltype(mutex)> lock(mutex); |
1092 | - if (!surface.has_id()) |
1093 | + if (!surface->has_id()) |
1094 | { |
1095 | - if (!surface.has_error()) |
1096 | - surface.set_error("Error processing surface create response, no ID (disconnected?)"); |
1097 | + if (!surface->has_error()) |
1098 | + surface->set_error("Error processing surface create response, no ID (disconnected?)"); |
1099 | |
1100 | callback(this, context); |
1101 | create_wait_handle.result_received(); |
1102 | @@ -299,11 +307,11 @@ |
1103 | std::lock_guard<decltype(mutex)> lock(mutex); |
1104 | |
1105 | buffer_stream = buffer_stream_factory-> |
1106 | - make_producer_stream(connection, *server, surface.buffer_stream(), name); |
1107 | + make_producer_stream(connection, *server, surface->buffer_stream(), name); |
1108 | |
1109 | - for(int i = 0; i < surface.attributes_size(); i++) |
1110 | + for(int i = 0; i < surface->attributes_size(); i++) |
1111 | { |
1112 | - auto const& attrib = surface.attributes(i); |
1113 | + auto const& attrib = surface->attributes(i); |
1114 | attrib_cache[attrib.attrib()] = attrib.ivalue(); |
1115 | } |
1116 | } |
1117 | @@ -312,7 +320,7 @@ |
1118 | } |
1119 | catch (std::exception const& error) |
1120 | { |
1121 | - surface.set_error(std::string{"Error processing Surface creating response:"} + |
1122 | + surface->set_error(std::string{"Error processing Surface creating response:"} + |
1123 | boost::diagnostic_information(error)); |
1124 | } |
1125 | |
1126 | @@ -331,7 +339,7 @@ |
1127 | was_valid = true; |
1128 | valid_surfaces.erase(this); |
1129 | } |
1130 | - if (this->surface.has_error()) |
1131 | + if (this->surface->has_error()) |
1132 | was_valid = false; |
1133 | |
1134 | MirWaitHandle* wait_handle{nullptr}; |
1135 | @@ -350,29 +358,28 @@ |
1136 | |
1137 | MirWaitHandle* MirSurface::configure_cursor(MirCursorConfiguration const* cursor) |
1138 | { |
1139 | - mp::CursorSetting setting; |
1140 | + auto setting = mcl::make_protobuf_object<mp::CursorSetting>(); |
1141 | |
1142 | { |
1143 | std::unique_lock<decltype(mutex)> lock(mutex); |
1144 | - setting.mutable_surfaceid()->CopyFrom(surface.id()); |
1145 | + setting->mutable_surfaceid()->CopyFrom(surface->id()); |
1146 | if (cursor) |
1147 | { |
1148 | if (cursor->stream != nullptr) |
1149 | { |
1150 | - setting.mutable_buffer_stream()->set_value(cursor->stream->rpc_id().as_value()); |
1151 | - setting.set_hotspot_x(cursor->hotspot_x); |
1152 | - setting.set_hotspot_y(cursor->hotspot_y); |
1153 | + setting->mutable_buffer_stream()->set_value(cursor->stream->rpc_id().as_value()); |
1154 | + setting->set_hotspot_x(cursor->hotspot_x); |
1155 | + setting->set_hotspot_y(cursor->hotspot_y); |
1156 | } |
1157 | else if (cursor->name != mir_disabled_cursor_name) |
1158 | { |
1159 | - setting.set_name(cursor->name.c_str()); |
1160 | + setting->set_name(cursor->name.c_str()); |
1161 | } |
1162 | - |
1163 | } |
1164 | } |
1165 | |
1166 | configure_cursor_wait_handle.expect_result(); |
1167 | - server->configure_cursor(0, &setting, &void_response, |
1168 | + server->configure_cursor(0, setting.get(), void_response.get(), |
1169 | google::protobuf::NewCallback(this, &MirSurface::on_cursor_configured)); |
1170 | |
1171 | return &configure_cursor_wait_handle; |
1172 | @@ -392,14 +399,14 @@ |
1173 | |
1174 | std::unique_lock<decltype(mutex)> lock(mutex); |
1175 | |
1176 | - mp::SurfaceSetting setting; |
1177 | - setting.mutable_surfaceid()->CopyFrom(surface.id()); |
1178 | - setting.set_attrib(at); |
1179 | - setting.set_ivalue(value); |
1180 | + auto setting = mcl::make_protobuf_object<mp::SurfaceSetting>(); |
1181 | + setting->mutable_surfaceid()->CopyFrom(surface->id()); |
1182 | + setting->set_attrib(at); |
1183 | + setting->set_ivalue(value); |
1184 | lock.unlock(); |
1185 | |
1186 | configure_wait_handle.expect_result(); |
1187 | - server->configure_surface(0, &setting, &configure_result, |
1188 | + server->configure_surface(0, setting.get(), configure_result.get(), |
1189 | google::protobuf::NewCallback(this, &MirSurface::on_configured)); |
1190 | |
1191 | return &configure_wait_handle; |
1192 | @@ -421,12 +428,12 @@ |
1193 | return false; |
1194 | } |
1195 | |
1196 | - mp::CoordinateTranslationRequest request; |
1197 | + auto request = mcl::make_protobuf_object<mp::CoordinateTranslationRequest>(); |
1198 | |
1199 | - request.set_x(x); |
1200 | - request.set_y(y); |
1201 | - *request.mutable_surfaceid() = surface.id(); |
1202 | - mp::CoordinateTranslationResponse response; |
1203 | + request->set_x(x); |
1204 | + request->set_y(y); |
1205 | + *request->mutable_surfaceid() = surface->id(); |
1206 | + auto response = mcl::make_protobuf_object<mp::CoordinateTranslationResponse>(); |
1207 | |
1208 | MirWaitHandle signal; |
1209 | signal.expect_result(); |
1210 | @@ -436,27 +443,27 @@ |
1211 | |
1212 | debug->translate_surface_to_screen( |
1213 | nullptr, |
1214 | - &request, |
1215 | - &response, |
1216 | + request.get(), |
1217 | + response.get(), |
1218 | google::protobuf::NewCallback(&signal_response_received, &signal)); |
1219 | } |
1220 | |
1221 | signal.wait_for_one(); |
1222 | |
1223 | - *screen_x = response.x(); |
1224 | - *screen_y = response.y(); |
1225 | - return !response.has_error(); |
1226 | + *screen_x = response->x(); |
1227 | + *screen_y = response->y(); |
1228 | + return !response->has_error(); |
1229 | } |
1230 | |
1231 | void MirSurface::on_configured() |
1232 | { |
1233 | std::lock_guard<decltype(mutex)> lock(mutex); |
1234 | |
1235 | - if (configure_result.has_surfaceid() && |
1236 | - configure_result.surfaceid().value() == surface.id().value() && |
1237 | - configure_result.has_attrib()) |
1238 | + if (configure_result->has_surfaceid() && |
1239 | + configure_result->surfaceid().value() == surface->id().value() && |
1240 | + configure_result->has_attrib()) |
1241 | { |
1242 | - int a = configure_result.attrib(); |
1243 | + int a = configure_result->attrib(); |
1244 | |
1245 | switch (a) |
1246 | { |
1247 | @@ -465,10 +472,10 @@ |
1248 | case mir_surface_attrib_focus: |
1249 | case mir_surface_attrib_dpi: |
1250 | case mir_surface_attrib_preferred_orientation: |
1251 | - if (configure_result.has_ivalue()) |
1252 | - attrib_cache[a] = configure_result.ivalue(); |
1253 | + if (configure_result->has_ivalue()) |
1254 | + attrib_cache[a] = configure_result->ivalue(); |
1255 | else |
1256 | - assert(configure_result.has_error()); |
1257 | + assert(configure_result->has_error()); |
1258 | break; |
1259 | default: |
1260 | assert(false); |
1261 | @@ -513,9 +520,9 @@ |
1262 | std::placeholders::_1, |
1263 | context); |
1264 | |
1265 | - if (surface.fd_size() > 0 && handle_event_callback) |
1266 | + if (surface->fd_size() > 0 && handle_event_callback) |
1267 | { |
1268 | - auto input_dispatcher = input_platform->create_input_receiver(surface.fd(0), |
1269 | + auto input_dispatcher = input_platform->create_input_receiver(surface->fd(0), |
1270 | keymapper, |
1271 | handle_event_callback); |
1272 | input_thread = std::make_shared<md::ThreadedDispatcher>("Input dispatch", input_dispatcher); |
1273 | @@ -587,7 +594,7 @@ |
1274 | { |
1275 | { |
1276 | std::lock_guard<decltype(mutex)> lock(mutex); |
1277 | - if (modify_result.has_error()) |
1278 | + if (modify_result->has_error()) |
1279 | { |
1280 | // TODO return errors like lp:~vanvugt/mir/wait-result |
1281 | } |
1282 | @@ -597,14 +604,14 @@ |
1283 | |
1284 | MirWaitHandle* MirSurface::modify(MirSurfaceSpec const& spec) |
1285 | { |
1286 | - mp::SurfaceModifications mods; |
1287 | + auto mods = mcl::make_protobuf_object<mp::SurfaceModifications>(); |
1288 | |
1289 | { |
1290 | std::unique_lock<decltype(mutex)> lock(mutex); |
1291 | - mods.mutable_surface_id()->set_value(surface.id().value()); |
1292 | + mods->mutable_surface_id()->set_value(surface->id().value()); |
1293 | } |
1294 | |
1295 | - auto const surface_specification = mods.mutable_surface_specification(); |
1296 | + auto const surface_specification = mods->mutable_surface_specification(); |
1297 | |
1298 | #define COPY_IF_SET(field)\ |
1299 | if (spec.field.is_set())\ |
1300 | @@ -678,7 +685,7 @@ |
1301 | } |
1302 | |
1303 | modify_wait_handle.expect_result(); |
1304 | - server->modify_surface(0, &mods, &modify_result, |
1305 | + server->modify_surface(0, mods.get(), modify_result.get(), |
1306 | google::protobuf::NewCallback(this, &MirSurface::on_modified)); |
1307 | |
1308 | return &modify_wait_handle; |
1309 | |
1310 | === modified file 'src/client/mir_surface.h' |
1311 | --- src/client/mir_surface.h 2015-06-10 12:01:33 +0000 |
1312 | +++ src/client/mir_surface.h 2015-06-16 23:39:42 +0000 |
1313 | @@ -65,7 +65,7 @@ |
1314 | MirSurfaceSpec(MirConnection* connection, int width, int height, MirPixelFormat format); |
1315 | MirSurfaceSpec(MirConnection* connection, MirSurfaceParameters const& params); |
1316 | |
1317 | - mir::protobuf::SurfaceParameters serialize() const; |
1318 | + std::unique_ptr<mir::protobuf::SurfaceParameters> serialize() const; |
1319 | |
1320 | struct AspectRatio { unsigned width; unsigned height; }; |
1321 | |
1322 | @@ -178,16 +178,15 @@ |
1323 | |
1324 | mir::protobuf::DisplayServer::Stub* server{nullptr}; |
1325 | mir::protobuf::Debug::Stub* debug{nullptr}; |
1326 | - mir::protobuf::Surface surface; |
1327 | - mir::protobuf::BufferRequest buffer_request; |
1328 | - mir::protobuf::PersistentSurfaceId persistent_id; |
1329 | + std::unique_ptr<mir::protobuf::Surface> surface; |
1330 | + std::unique_ptr<mir::protobuf::PersistentSurfaceId> persistent_id; |
1331 | std::string error_message; |
1332 | std::string name; |
1333 | - mir::protobuf::Void void_response; |
1334 | + std::unique_ptr<mir::protobuf::Void> void_response; |
1335 | |
1336 | void on_modified(); |
1337 | MirWaitHandle modify_wait_handle; |
1338 | - mir::protobuf::Void modify_result; |
1339 | + std::unique_ptr<mir::protobuf::Void> modify_result; |
1340 | |
1341 | MirConnection* const connection{nullptr}; |
1342 | |
1343 | @@ -201,7 +200,7 @@ |
1344 | std::shared_ptr<mir::input::receiver::InputPlatform> const input_platform; |
1345 | std::shared_ptr<mir::input::receiver::XKBMapper> const keymapper; |
1346 | |
1347 | - mir::protobuf::SurfaceSetting configure_result; |
1348 | + std::unique_ptr<mir::protobuf::SurfaceSetting> configure_result; |
1349 | |
1350 | // Cache of latest SurfaceSettings returned from the server |
1351 | int attrib_cache[mir_surface_attribs]; |
1352 | |
1353 | === modified file 'src/client/rpc/mir_protobuf_rpc_channel.cpp' |
1354 | --- src/client/rpc/mir_protobuf_rpc_channel.cpp 2015-06-03 17:16:04 +0000 |
1355 | +++ src/client/rpc/mir_protobuf_rpc_channel.cpp 2015-06-16 23:39:42 +0000 |
1356 | @@ -25,6 +25,7 @@ |
1357 | #include "../display_configuration.h" |
1358 | #include "../lifecycle_control.h" |
1359 | #include "../event_sink.h" |
1360 | +#include "../make_protobuf_object.h" |
1361 | #include "mir/variable_length_array.h" |
1362 | #include "mir/events/event_private.h" |
1363 | |
1364 | @@ -236,24 +237,24 @@ |
1365 | |
1366 | void mclr::MirProtobufRpcChannel::process_event_sequence(std::string const& event) |
1367 | { |
1368 | - mir::protobuf::EventSequence seq; |
1369 | - |
1370 | - seq.ParseFromString(event); |
1371 | - |
1372 | - if (seq.has_display_configuration()) |
1373 | - { |
1374 | - display_configuration->update_configuration(seq.display_configuration()); |
1375 | - } |
1376 | - |
1377 | - if (seq.has_lifecycle_event()) |
1378 | - { |
1379 | - lifecycle_control->call_lifecycle_event_handler(seq.lifecycle_event().new_state()); |
1380 | - } |
1381 | - |
1382 | - int const nevents = seq.event_size(); |
1383 | + auto seq = mcl::make_protobuf_object<mir::protobuf::EventSequence>(); |
1384 | + |
1385 | + seq->ParseFromString(event); |
1386 | + |
1387 | + if (seq->has_display_configuration()) |
1388 | + { |
1389 | + display_configuration->update_configuration(seq->display_configuration()); |
1390 | + } |
1391 | + |
1392 | + if (seq->has_lifecycle_event()) |
1393 | + { |
1394 | + lifecycle_control->call_lifecycle_event_handler(seq->lifecycle_event().new_state()); |
1395 | + } |
1396 | + |
1397 | + int const nevents = seq->event_size(); |
1398 | for (int i = 0; i != nevents; ++i) |
1399 | { |
1400 | - mir::protobuf::Event const& event = seq.event(i); |
1401 | + mir::protobuf::Event const& event = seq->event(i); |
1402 | if (event.has_raw()) |
1403 | { |
1404 | std::string const& raw_event = event.raw(); |
1405 | @@ -320,7 +321,7 @@ |
1406 | */ |
1407 | std::lock_guard<decltype(read_mutex)> lock(read_mutex); |
1408 | |
1409 | - auto result = std::make_unique<mir::protobuf::wire::Result>(); |
1410 | + auto result = mcl::make_protobuf_object<mir::protobuf::wire::Result>(); |
1411 | try |
1412 | { |
1413 | uint16_t message_size; |
PASSED: Continuous integration, rev:2671 jenkins. qa.ubuntu. com/job/ mir-ci/ 4120/ jenkins. qa.ubuntu. com/job/ mir-android- vivid-i386- build/2880 jenkins. qa.ubuntu. com/job/ mir-clang- wily-amd64- build/393 jenkins. qa.ubuntu. com/job/ mir-mediumtests -vivid- touch/2828 jenkins. qa.ubuntu. com/job/ mir-wily- amd64-ci/ 276 jenkins. qa.ubuntu. com/job/ mir-wily- amd64-ci/ 276/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 2828 jenkins. qa.ubuntu. com/job/ mir-mediumtests -builder- vivid-armhf/ 2828/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ mir-mediumtests -runner- mako/5658 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 21235
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/mir- ci/4120/ rebuild
http://