Merge lp:~thomas-voss/location-service/add-standalone-provider-runner into lp:location-service/trunk

Proposed by Thomas Voß
Status: Merged
Approved by: Manuel de la Peña
Approved revision: 114
Merged at revision: 107
Proposed branch: lp:~thomas-voss/location-service/add-standalone-provider-runner
Merge into: lp:location-service/trunk
Prerequisite: lp:~thomas-voss/location-service/expose-remote-provider-interface-as-part-of-dev-package
Diff against target: 1040 lines (+688/-58)
14 files modified
debian/ubuntu-location-service-bin.install (+1/-0)
src/location_service/com/ubuntu/location/CMakeLists.txt (+37/-0)
src/location_service/com/ubuntu/location/providers/remote/provider.cpp (+143/-37)
src/location_service/com/ubuntu/location/providers/remote/provider.h (+4/-2)
src/location_service/com/ubuntu/location/service/daemon.cpp (+2/-2)
src/location_service/com/ubuntu/location/service/daemon.h (+1/-16)
src/location_service/com/ubuntu/location/service/daemon_main.cpp (+1/-1)
src/location_service/com/ubuntu/location/service/dbus_connection_factory.h (+52/-0)
src/location_service/com/ubuntu/location/service/provider_daemon.cpp (+147/-0)
src/location_service/com/ubuntu/location/service/provider_daemon.h (+69/-0)
src/location_service/com/ubuntu/location/service/provider_daemon_main.cpp (+30/-0)
tests/CMakeLists.txt (+3/-0)
tests/remote_provider_test.cpp (+4/-0)
tests/remote_providerd_test.cpp (+194/-0)
To merge this branch: bzr merge lp:~thomas-voss/location-service/add-standalone-provider-runner
Reviewer Review Type Date Requested Status
Manuel de la Peña (community) Approve
PS Jenkins bot continuous-integration Needs Fixing
Review via email: mp+234941@code.launchpad.net

This proposal supersedes a proposal from 2014-09-17.

Commit message

Add a standalone daemon for executing providers out of process.

Description of the change

Add a standalone daemon for executing providers out of process.

To post a comment you must log in.
115. By Thomas Voß

Adjust copyright years.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:114
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~thomas-voss/location-service/add-standalone-provider-runner/+merge/234941/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/location-service-ci/286/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/location-service-utopic-amd64-ci/193/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/location-service-utopic-armhf-ci/193/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/location-service-utopic-i386-ci/193/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/location-service-ci/286/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Manuel de la Peña (mandel) :
review: Approve
116. By Thomas Voß

Install provider daemon.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/ubuntu-location-service-bin.install'
2--- debian/ubuntu-location-service-bin.install 2014-07-31 12:12:43 +0000
3+++ debian/ubuntu-location-service-bin.install 2014-09-17 13:26:40 +0000
4@@ -1,5 +1,6 @@
5 etc/dbus-1/system.d/
6 etc/init/*
7 usr/share/upstart/sessions/ubuntu-location-service-trust-stored.conf
8+usr/bin/ubuntu-location-service-providerd
9 usr/bin/ubuntu-location-serviced
10 usr/bin/ubuntu-location-serviced-cli
11
12=== modified file 'src/location_service/com/ubuntu/location/CMakeLists.txt'
13--- src/location_service/com/ubuntu/location/CMakeLists.txt 2014-09-17 13:26:40 +0000
14+++ src/location_service/com/ubuntu/location/CMakeLists.txt 2014-09-17 13:26:40 +0000
15@@ -131,12 +131,24 @@
16 )
17
18 add_library(
19+ ubuntu-location-service-provider-daemon
20+
21+ service/provider_daemon.cpp
22+)
23+
24+add_library(
25 ubuntu-location-service-daemon
26
27 service/daemon.cpp
28 )
29
30 add_executable(
31+ ubuntu-location-service-providerd
32+
33+ service/provider_daemon_main.cpp
34+)
35+
36+add_executable(
37 ubuntu-location-serviced
38
39 service/daemon_main.cpp
40@@ -149,12 +161,32 @@
41 )
42
43 target_link_libraries(
44+ ubuntu-location-service-provider-daemon
45+
46+ ubuntu-location-service
47+)
48+
49+target_link_libraries(
50 ubuntu-location-service-daemon
51
52 ubuntu-location-service
53 )
54
55 target_link_libraries(
56+ ubuntu-location-service-providerd
57+
58+ ubuntu-location-service-provider-daemon
59+
60+ ${ENABLED_PROVIDER_TARGETS}
61+
62+ ${Boost_LIBRARIES}
63+ ${DBUS_LIBRARIES}
64+ ${DBUS_CPP_LIBRARIES}
65+ ${GLog_LIBRARY}
66+ ${GFlags_LIBRARY}
67+)
68+
69+target_link_libraries(
70 ubuntu-location-serviced
71
72 ubuntu-location-service-daemon
73@@ -183,6 +215,11 @@
74 )
75
76 install(
77+ TARGETS ubuntu-location-service-providerd
78+ DESTINATION ${CMAKE_INSTALL_BINDIR}
79+)
80+
81+install(
82 TARGETS ubuntu-location-serviced
83 DESTINATION ${CMAKE_INSTALL_BINDIR}
84 )
85
86=== modified file 'src/location_service/com/ubuntu/location/providers/remote/provider.cpp'
87--- src/location_service/com/ubuntu/location/providers/remote/provider.cpp 2014-09-17 13:26:40 +0000
88+++ src/location_service/com/ubuntu/location/providers/remote/provider.cpp 2014-09-17 13:26:40 +0000
89@@ -26,6 +26,10 @@
90 #include <core/dbus/signal.h>
91 #include <core/dbus/asio/executor.h>
92
93+#include <core/posix/this_process.h>
94+
95+#include <boost/asio.hpp>
96+
97 #include <thread>
98
99 namespace cul = com::ubuntu::location;
100@@ -35,6 +39,73 @@
101
102 namespace
103 {
104+struct Runtime
105+{
106+ static Runtime& instance()
107+ {
108+ static Runtime runtime;
109+ return runtime;
110+ }
111+
112+ Runtime()
113+ : keep_alive{io_service},
114+ worker1
115+ {
116+ [this]()
117+ {
118+ io_service.run();
119+ }
120+ },
121+ worker2
122+ {
123+ [this]()
124+ {
125+ io_service.run();
126+ }
127+ }
128+ {
129+ }
130+
131+ ~Runtime()
132+ {
133+ io_service.stop();
134+
135+ if (worker1.joinable())
136+ worker1.join();
137+
138+ if (worker2.joinable())
139+ worker2.join();
140+ }
141+
142+ boost::asio::io_service io_service;
143+ boost::asio::io_service::work keep_alive;
144+ std::thread worker1;
145+ std::thread worker2;
146+};
147+
148+core::dbus::Bus::Ptr bus_from_name(const std::string& bus_name)
149+{
150+ core::dbus::Bus::Ptr bus;
151+
152+ if (bus_name == "system")
153+ bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::system);
154+ else if (bus_name == "session")
155+ bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
156+ else if (bus_name == "system_with_address_from_env")
157+ bus = std::make_shared<core::dbus::Bus>(core::posix::this_process::env::get_or_throw("DBUS_SYSTEM_BUS_ADDRESS"));
158+ else if (bus_name == "session_with_address_from_env")
159+ bus = std::make_shared<core::dbus::Bus>(core::posix::this_process::env::get_or_throw("DBUS_SESSION_BUS_ADDRESS"));
160+
161+ if (not bus) throw std::runtime_error
162+ {
163+ "Could not create bus for name: " + bus_name
164+ };
165+
166+ bus->install_executor(core::dbus::asio::make_executor(bus, Runtime::instance().io_service));
167+
168+ return bus;
169+}
170+
171 void throw_if_error(const dbus::Result<void>& result)
172 {
173 if (result.is_error()) throw std::runtime_error
174@@ -52,13 +123,6 @@
175 };
176 return result.value();
177 }
178-
179-dbus::Bus::Ptr the_system_bus()
180-{
181- dbus::Bus::Ptr system_bus = std::make_shared<dbus::Bus>(dbus::WellKnownBus::system);
182- system_bus->install_executor(core::dbus::asio::make_executor(system_bus));
183- return system_bus;
184-}
185 }
186
187 struct remote::Provider::Stub::Private
188@@ -84,12 +148,14 @@
189
190 cul::Provider::Ptr remote::Provider::Stub::create_instance(const cul::ProviderFactory::Configuration& config)
191 {
192+ auto bus_name = config.count(Stub::key_bus) > 0 ? config.get<std::string>(Stub::key_bus) :
193+ "system";
194 auto name = config.count(Stub::key_name) > 0 ? config.get<std::string>(Stub::key_name) :
195 throw std::runtime_error("Missing bus-name");
196 auto path = config.count(Stub::key_path) > 0 ? config.get<std::string>(Stub::key_path) :
197 throw std::runtime_error("Missing bus-path");
198
199- auto bus = the_system_bus();
200+ auto bus = bus_from_name(bus_name);
201 auto service = dbus::Service::use_service(bus, name);
202 auto object = service->object_for_path(path);
203
204@@ -122,11 +188,12 @@
205
206 remote::Provider::Stub::~Stub() noexcept
207 {
208+ VLOG(10) << __PRETTY_FUNCTION__;
209 }
210
211 bool remote::Provider::Stub::matches_criteria(const cul::Criteria& criteria)
212 {
213- VLOG(10) << __PRETTY_FUNCTION__ << std::endl;
214+ VLOG(10) << __PRETTY_FUNCTION__ << std::endl;
215 return throw_if_error_or_return(d->stub.object->transact_method<remote::Interface::MatchesCriteria, bool>(criteria));
216 }
217
218@@ -150,56 +217,108 @@
219
220 void remote::Provider::Stub::on_reference_location_updated(const cul::Update<cul::Position>& position)
221 {
222- VLOG(10) << __PRETTY_FUNCTION__;
223- throw_if_error(d->stub.object->transact_method<remote::Interface::OnReferenceLocationChanged, void>(position));
224+ std::weak_ptr<Private> wp{d};
225+ Runtime::instance().io_service.post([wp, position]()
226+ {
227+ auto sp = wp.lock();
228+
229+ if (not sp)
230+ return;
231+
232+ try
233+ {
234+ throw_if_error(sp->stub.object->transact_method<remote::Interface::OnReferenceLocationChanged, void>(position));
235+ } catch(const std::exception& e)
236+ {
237+ // We drop the error and just log it for post-mortem inspection.
238+ LOG(WARNING) << "Transaction<remote::Interface::OnReferenceLocationChanged>: " << e.what();
239+ }
240+ });
241 }
242
243 void remote::Provider::Stub::on_reference_velocity_updated(const cul::Update<cul::Velocity>& velocity)
244 {
245- VLOG(10) << __PRETTY_FUNCTION__;
246- throw_if_error(d->stub.object->transact_method<remote::Interface::OnReferenceVelocityChanged, void>(velocity));
247+ std::weak_ptr<Private> wp{d};
248+ Runtime::instance().io_service.post([wp, velocity]()
249+ {
250+ auto sp = wp.lock();
251+
252+ if (not sp)
253+ return;
254+
255+ try
256+ {
257+ throw_if_error(sp->stub.object->transact_method<remote::Interface::OnReferenceVelocityChanged, void>(velocity));
258+ } catch(const std::exception& e)
259+ {
260+ // We drop the error and just log it for post-mortem inspection.
261+ LOG(WARNING) << "Transaction<remote::Interface::OnReferenceVelocityChanged>: " << e.what();
262+ }
263+ });
264 }
265
266 void remote::Provider::Stub::on_reference_heading_updated(const cul::Update<cul::Heading>& heading)
267 {
268- VLOG(10) << __PRETTY_FUNCTION__;
269- throw_if_error(d->stub.object->transact_method<remote::Interface::OnReferenceHeadingChanged, void>(heading));
270+ std::weak_ptr<Private> wp{d};
271+ Runtime::instance().io_service.post([wp, heading]()
272+ {
273+ auto sp = wp.lock();
274+
275+ if (not sp)
276+ return;
277+
278+ try
279+ {
280+ throw_if_error(sp->stub.object->transact_method<remote::Interface::OnReferenceHeadingChanged, void>(heading));
281+ } catch(const std::exception& e)
282+ {
283+ // We drop the error and just log it for post-mortem inspection.
284+ LOG(WARNING) << "Transaction<remote::Interface::OnReferenceHeadingChanged>: " << e.what();
285+ }
286+ });
287 }
288
289 void remote::Provider::Stub::start_position_updates()
290 {
291- VLOG(10) << __PRETTY_FUNCTION__;
292+ VLOG(10) << "> " << __PRETTY_FUNCTION__;
293 throw_if_error(d->stub.object->transact_method<remote::Interface::StartPositionUpdates, void>());
294+ VLOG(10) << "< " << __PRETTY_FUNCTION__;
295 }
296
297 void remote::Provider::Stub::stop_position_updates()
298 {
299- VLOG(10) << __PRETTY_FUNCTION__;
300+ VLOG(10) << "> " << __PRETTY_FUNCTION__;
301 throw_if_error(d->stub.object->transact_method<remote::Interface::StopPositionUpdates, void>());
302+ VLOG(10) << "< " << __PRETTY_FUNCTION__;
303 }
304
305 void remote::Provider::Stub::start_heading_updates()
306 {
307- VLOG(10) << __PRETTY_FUNCTION__;
308+ VLOG(10) << "> " << __PRETTY_FUNCTION__;
309 throw_if_error(d->stub.object->transact_method<remote::Interface::StartHeadingUpdates, void>());
310+ VLOG(10) << "< " << __PRETTY_FUNCTION__;
311 }
312
313 void remote::Provider::Stub::stop_heading_updates()
314 {
315- VLOG(10) << __PRETTY_FUNCTION__;
316+ VLOG(10) << "> " << __PRETTY_FUNCTION__;
317 throw_if_error(d->stub.object->transact_method<remote::Interface::StopHeadingUpdates, void>());
318+ VLOG(10) << "< " << __PRETTY_FUNCTION__;
319 }
320
321 void remote::Provider::Stub::start_velocity_updates()
322 {
323- VLOG(10) << __PRETTY_FUNCTION__;
324+ VLOG(10) << "> " << __PRETTY_FUNCTION__;
325 throw_if_error(d->stub.object->transact_method<remote::Interface::StartVelocityUpdates, void>());
326+ VLOG(10) << "< " << __PRETTY_FUNCTION__;
327+
328 }
329
330 void remote::Provider::Stub::stop_velocity_updates()
331 {
332- VLOG(10) << __PRETTY_FUNCTION__;
333+ VLOG(10) << "> " << __PRETTY_FUNCTION__;
334 throw_if_error(d->stub.object->transact_method<remote::Interface::StopVelocityUpdates, void>());
335+ VLOG(10) << "< " << __PRETTY_FUNCTION__;
336 }
337
338 struct remote::Provider::Skeleton::Private
339@@ -212,14 +331,17 @@
340 {
341 impl->updates().position.connect([this](const cul::Update<cul::Position>& position)
342 {
343+ VLOG(100) << "Position changed reported by impl: " << position;
344 skeleton.signals.position_changed->emit(position.value);
345 }),
346 impl->updates().heading.connect([this](const cul::Update<cul::Heading>& heading)
347 {
348+ VLOG(100) << "Heading changed reported by impl: " << heading;
349 skeleton.signals.heading_changed->emit(heading.value);
350 }),
351 impl->updates().velocity.connect([this](const cul::Update<cul::Velocity>& velocity)
352 {
353+ VLOG(100) << "Velocity changed reported by impl: " << velocity;
354 skeleton.signals.velocity_changed->emit(velocity.value);
355 })
356 }
357@@ -243,22 +365,6 @@
358 : cul::Provider(),
359 d(new Private(config))
360 {
361- // Wire up to updates.
362- d->impl->updates().position.connect([this](const cul::Update<cul::Position>& position)
363- {
364- d->skeleton.signals.position_changed->emit(position.value);
365- });
366-
367- d->impl->updates().heading.connect([this](const cul::Update<cul::Heading>& heading)
368- {
369- d->skeleton.signals.heading_changed->emit(heading.value);
370- });
371-
372- d->impl->updates().velocity.connect([this](const cul::Update<cul::Velocity>& velocity)
373- {
374- d->skeleton.signals.velocity_changed->emit(velocity.value);
375- });
376-
377 // And install method handlers.
378 d->skeleton.object->install_method_handler<remote::Interface::MatchesCriteria>([this](const dbus::Message::Ptr & msg)
379 {
380
381=== modified file 'src/location_service/com/ubuntu/location/providers/remote/provider.h'
382--- src/location_service/com/ubuntu/location/providers/remote/provider.h 2014-09-17 13:26:40 +0000
383+++ src/location_service/com/ubuntu/location/providers/remote/provider.h 2014-09-17 13:26:40 +0000
384@@ -48,6 +48,8 @@
385 // from the provided property bundle.
386 static Provider::Ptr create_instance(const ProviderFactory::Configuration&);
387
388+ // Name of the command line parameter for passing in the DBus to connect to.
389+ static constexpr const char* key_bus{"bus"};
390 // Name of the command line parameter for passing in the remote service name.
391 static constexpr const char* key_name{"name"};
392 // Name of the command line parameter for passing in the path of the remote provider impl.
393@@ -76,7 +78,7 @@
394
395 private:
396 struct Private;
397- std::unique_ptr<Private> d;
398+ std::shared_ptr<Private> d;
399 };
400
401 class Skeleton : public com::ubuntu::location::Provider
402@@ -106,7 +108,7 @@
403
404 private:
405 struct Private;
406- std::unique_ptr<Private> d;
407+ std::shared_ptr<Private> d;
408 };
409 };
410 }
411
412=== modified file 'src/location_service/com/ubuntu/location/service/daemon.cpp'
413--- src/location_service/com/ubuntu/location/service/daemon.cpp 2014-08-13 13:08:22 +0000
414+++ src/location_service/com/ubuntu/location/service/daemon.cpp 2014-09-17 13:26:40 +0000
415@@ -89,7 +89,7 @@
416 location::service::Daemon::Configuration location::service::Daemon::Configuration::from_command_line_args(
417 int argc,
418 const char** argv,
419- location::service::Daemon::DBusConnectionFactory factory)
420+ location::service::DBusConnectionFactory factory)
421 {
422 location::service::Daemon::Configuration result;
423
424@@ -289,7 +289,7 @@
425 location::service::Daemon::Cli::Configuration location::service::Daemon::Cli::Configuration::from_command_line_args(
426 int argc,
427 const char** argv,
428- location::service::Daemon::DBusConnectionFactory factory)
429+ location::service::DBusConnectionFactory factory)
430 {
431 location::service::Daemon::Cli::Configuration result;
432
433
434=== modified file 'src/location_service/com/ubuntu/location/service/daemon.h'
435--- src/location_service/com/ubuntu/location/service/daemon.h 2014-07-29 10:51:48 +0000
436+++ src/location_service/com/ubuntu/location/service/daemon.h 2014-09-17 13:26:40 +0000
437@@ -20,7 +20,7 @@
438
439 #include <com/ubuntu/location/configuration.h>
440
441-#include <core/dbus/bus.h>
442+#include <com/ubuntu/location/service/dbus_connection_factory.h>
443
444 #include <iosfwd>
445 #include <string>
446@@ -38,21 +38,6 @@
447 */
448 struct Daemon
449 {
450- /** @brief Function signature for creating DBus connections. */
451- typedef std::function<core::dbus::Bus::Ptr(core::dbus::WellKnownBus)> DBusConnectionFactory;
452-
453- /** @brief Returns the default connection factory. */
454- static DBusConnectionFactory default_dbus_connection_factory()
455- {
456- return [](core::dbus::WellKnownBus bus)
457- {
458- return core::dbus::Bus::Ptr
459- {
460- new core::dbus::Bus(bus)
461- };
462- };
463- }
464-
465 /** @brief Describes the command-line interface to the daemon. */
466 struct Cli
467 {
468
469=== modified file 'src/location_service/com/ubuntu/location/service/daemon_main.cpp'
470--- src/location_service/com/ubuntu/location/service/daemon_main.cpp 2014-08-14 20:25:22 +0000
471+++ src/location_service/com/ubuntu/location/service/daemon_main.cpp 2014-09-17 13:26:40 +0000
472@@ -44,7 +44,7 @@
473 {
474 FLAGS_logtostderr = true;
475 VLOG(1) << "Problem creating directory for log files: " << ec << "."
476- << "Falling back to stderr logging.";
477+ << "Falling back to stderr logging.";
478 }
479
480 FLAGS_log_dir = log_dir;
481
482=== added file 'src/location_service/com/ubuntu/location/service/dbus_connection_factory.h'
483--- src/location_service/com/ubuntu/location/service/dbus_connection_factory.h 1970-01-01 00:00:00 +0000
484+++ src/location_service/com/ubuntu/location/service/dbus_connection_factory.h 2014-09-17 13:26:40 +0000
485@@ -0,0 +1,52 @@
486+/*
487+ * Copyright © 2012-2013 Canonical Ltd.
488+ *
489+ * This program is free software: you can redistribute it and/or modify it
490+ * under the terms of the GNU Lesser General Public License version 3,
491+ * as published by the Free Software Foundation.
492+ *
493+ * This program is distributed in the hope that it will be useful,
494+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
495+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
496+ * GNU Lesser General Public License for more details.
497+ *
498+ * You should have received a copy of the GNU Lesser General Public License
499+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
500+ *
501+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
502+ */
503+#ifndef LOCATION_SERVICE_COM_UBUNTU_LOCATION_SERVICE_DBUS_CONNECTION_FACTORY_H_
504+#define LOCATION_SERVICE_COM_UBUNTU_LOCATION_SERVICE_DBUS_CONNECTION_FACTORY_H_
505+
506+#include <core/dbus/bus.h>
507+
508+#include <functional>
509+
510+namespace com
511+{
512+namespace ubuntu
513+{
514+namespace location
515+{
516+namespace service
517+{
518+/** @brief Function signature for creating DBus connections. */
519+typedef std::function<core::dbus::Bus::Ptr(core::dbus::WellKnownBus)> DBusConnectionFactory;
520+
521+/** @brief Returns the default connection factory. */
522+static DBusConnectionFactory default_dbus_connection_factory()
523+{
524+ return [](core::dbus::WellKnownBus bus)
525+ {
526+ return core::dbus::Bus::Ptr
527+ {
528+ new core::dbus::Bus(bus)
529+ };
530+ };
531+}
532+}
533+}
534+}
535+}
536+
537+#endif // LOCATION_SERVICE_COM_UBUNTU_LOCATION_SERVICE_DBUS_CONNECTION_FACTORY_H_
538
539=== added file 'src/location_service/com/ubuntu/location/service/provider_daemon.cpp'
540--- src/location_service/com/ubuntu/location/service/provider_daemon.cpp 1970-01-01 00:00:00 +0000
541+++ src/location_service/com/ubuntu/location/service/provider_daemon.cpp 2014-09-17 13:26:40 +0000
542@@ -0,0 +1,147 @@
543+/*
544+ * Copyright © 2014 Canonical Ltd.
545+ *
546+ * This program is free software: you can redistribute it and/or modify it
547+ * under the terms of the GNU Lesser General Public License version 3,
548+ * as published by the Free Software Foundation.
549+ *
550+ * This program is distributed in the hope that it will be useful,
551+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
552+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
553+ * GNU Lesser General Public License for more details.
554+ *
555+ * You should have received a copy of the GNU Lesser General Public License
556+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
557+ *
558+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
559+ */
560+
561+#include <com/ubuntu/location/service/provider_daemon.h>
562+
563+#include <com/ubuntu/location/configuration.h>
564+#include <com/ubuntu/location/provider_factory.h>
565+
566+#include <com/ubuntu/location/providers/remote/skeleton.h>
567+
568+#include <com/ubuntu/location/service/configuration.h>
569+#include <com/ubuntu/location/service/program_options.h>
570+
571+#include <core/posix/signal.h>
572+
573+namespace location = com::ubuntu::location;
574+
575+namespace
576+{
577+location::ProgramOptions init_daemon_options()
578+{
579+ location::ProgramOptions options;
580+
581+ options.add("help", "Produces this help message");
582+ options.add<std::string>("service-name",
583+ "The name of the service under which the provider should be exposed.");
584+ options.add<std::string>("service-path",
585+ "The dbus object path under which the provider is known.");
586+ options.add<std::string>("provider",
587+ "The provider that should be exposed to the bus");
588+
589+ return options;
590+}
591+
592+location::ProgramOptions& mutable_daemon_options()
593+{
594+ static location::ProgramOptions options = init_daemon_options();
595+ return options;
596+}
597+}
598+
599+location::service::ProviderDaemon::Configuration location::service::ProviderDaemon::Configuration::from_command_line_args(
600+ int argc, const char** argv, location::service::DBusConnectionFactory factory)
601+{
602+ if (!mutable_daemon_options().parse_from_command_line_args(argc, argv))
603+ throw std::runtime_error{"Could not parse command-line, aborting..."};
604+
605+ location::service::ProviderDaemon::Configuration result;
606+
607+ result.connection = factory(mutable_daemon_options().bus());
608+
609+ auto service = core::dbus::Service::add_service(
610+ result.connection,
611+ mutable_daemon_options().value_for_key<std::string>("service-name"));
612+
613+ result.object = service->add_object_for_path(core::dbus::types::ObjectPath
614+ {
615+ mutable_daemon_options().value_for_key<std::string>("service-path")
616+ });
617+
618+ auto provider_name = mutable_daemon_options().value_for_key<std::string>("provider");
619+ location::Configuration config;
620+
621+ mutable_daemon_options().enumerate_unrecognized_options([&config, provider_name](const std::string& s)
622+ {
623+ std::stringstream in(s);
624+ std::string key, value;
625+
626+ std::getline(in, key, '=');
627+ std::getline(in, value, '=');
628+
629+ std::size_t pos = key.find(provider_name);
630+ if (pos == std::string::npos)
631+ return;
632+
633+ static const std::string option_marker{"--"};
634+ static const std::string scope_separator{"::"};
635+
636+ key = key.erase(key.find_first_of(option_marker), option_marker.size());
637+ key = key.erase(key.find_first_of(provider_name), provider_name.size());
638+ key = key.erase(key.find_first_of(scope_separator), scope_separator.size());
639+
640+ config.put(key, value);
641+ });
642+
643+ result.provider = location::ProviderFactory::instance().create_provider_for_name_with_config(
644+ provider_name,
645+ config);
646+
647+ return result;
648+}
649+
650+int location::service::ProviderDaemon::main(const location::service::ProviderDaemon::Configuration& configuration)
651+{
652+ auto trap = core::posix::trap_signals_for_all_subsequent_threads(
653+ {
654+ core::posix::Signal::sig_term,
655+ core::posix::Signal::sig_int
656+ });
657+
658+ trap->signal_raised().connect([trap](const core::posix::Signal&)
659+ {
660+ trap->stop();
661+ });
662+
663+ std::thread worker
664+ {
665+ [configuration]()
666+ {
667+ configuration.connection->run();
668+ }
669+ };
670+
671+ auto skeleton = location::providers::remote::skeleton::create_with_configuration(location::providers::remote::skeleton::Configuration
672+ {
673+ configuration.object,
674+ configuration.connection,
675+ configuration.provider
676+ });
677+
678+
679+ std::cout << "We are up and running" << std::endl;
680+
681+ trap->run();
682+
683+ configuration.connection->stop();
684+
685+ if (worker.joinable())
686+ worker.join();
687+
688+ return EXIT_SUCCESS;
689+}
690
691=== added file 'src/location_service/com/ubuntu/location/service/provider_daemon.h'
692--- src/location_service/com/ubuntu/location/service/provider_daemon.h 1970-01-01 00:00:00 +0000
693+++ src/location_service/com/ubuntu/location/service/provider_daemon.h 2014-09-17 13:26:40 +0000
694@@ -0,0 +1,69 @@
695+/*
696+ * Copyright © 2014 Canonical Ltd.
697+ *
698+ * This program is free software: you can redistribute it and/or modify it
699+ * under the terms of the GNU Lesser General Public License version 3,
700+ * as published by the Free Software Foundation.
701+ *
702+ * This program is distributed in the hope that it will be useful,
703+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
704+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
705+ * GNU Lesser General Public License for more details.
706+ *
707+ * You should have received a copy of the GNU Lesser General Public License
708+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
709+ *
710+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
711+ */
712+#ifndef LOCATION_SERVICE_COM_UBUNTU_LOCATION_SERVICE_PROVIDER_DAEMON_H_
713+#define LOCATION_SERVICE_COM_UBUNTU_LOCATION_SERVICE_PROVIDER_DAEMON_H_
714+
715+#include <com/ubuntu/location/provider.h>
716+
717+#include <com/ubuntu/location/service/dbus_connection_factory.h>
718+
719+#include <core/dbus/bus.h>
720+#include <core/dbus/object.h>
721+
722+namespace com
723+{
724+namespace ubuntu
725+{
726+namespace location
727+{
728+namespace service
729+{
730+// Provides a default out-of-process runner for known providers,
731+// leveraging the actual provider instance and a remote::Provider to
732+// expose it to the bus.
733+struct ProviderDaemon
734+{
735+ // Startup configuration goes here.
736+ struct Configuration
737+ {
738+ // Initializes a startup configuration from a command line.
739+ // Throws in case of issues.
740+ // Known parameters are:
741+ // --bus={system, session}: The bus to connect to.
742+ // --service-name=name: The name of the service under which the provider should be exposed.
743+ // --service-path=path: The dbus object path under which the provider is known.
744+ // --provider=name: The name of the actual provider implementation.
745+ static Configuration from_command_line_args(int argc, const char** argv, DBusConnectionFactory factory);
746+
747+ // The bus connection that should be used by the remote::Provider::Skeleton instance.
748+ core::dbus::Bus::Ptr connection;
749+ // The object on the bus that represents the remote::Provider::Skeleton.
750+ core::dbus::Object::Ptr object;
751+ // The actual provider implementation.
752+ Provider::Ptr provider;
753+ };
754+
755+ // Executes the daemon with the given configuration.
756+ static int main(const Configuration& configuration);
757+};
758+}
759+}
760+}
761+}
762+
763+#endif // LOCATION_SERVICE_COM_UBUNTU_LOCATION_SERVICE_PROVIDER_DAEMON_H_
764
765=== added file 'src/location_service/com/ubuntu/location/service/provider_daemon_main.cpp'
766--- src/location_service/com/ubuntu/location/service/provider_daemon_main.cpp 1970-01-01 00:00:00 +0000
767+++ src/location_service/com/ubuntu/location/service/provider_daemon_main.cpp 2014-09-17 13:26:40 +0000
768@@ -0,0 +1,30 @@
769+/*
770+ * Copyright © 2014 Canonical Ltd.
771+ *
772+ * This program is free software: you can redistribute it and/or modify it
773+ * under the terms of the GNU Lesser General Public License version 3,
774+ * as published by the Free Software Foundation.
775+ *
776+ * This program is distributed in the hope that it will be useful,
777+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
778+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
779+ * GNU Lesser General Public License for more details.
780+ *
781+ * You should have received a copy of the GNU Lesser General Public License
782+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
783+ *
784+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
785+ */
786+
787+#include <com/ubuntu/location/service/provider_daemon.h>
788+
789+namespace location = com::ubuntu::location;
790+
791+int main(int argc, const char** argv)
792+{
793+ return location::service::ProviderDaemon::main(
794+ location::service::ProviderDaemon::Configuration::from_command_line_args(
795+ argc,
796+ argv,
797+ location::service::default_dbus_connection_factory()));
798+}
799
800=== modified file 'tests/CMakeLists.txt'
801--- tests/CMakeLists.txt 2014-09-17 13:26:40 +0000
802+++ tests/CMakeLists.txt 2014-09-17 13:26:40 +0000
803@@ -37,6 +37,7 @@
804
805 ubuntu-location-service
806 ubuntu-location-service-connectivity
807+ ubuntu-location-service-provider-daemon
808 ubuntu-location-service-daemon
809
810 mongoose
811@@ -117,5 +118,7 @@
812 endif (LOCATION_SERVICE_ENABLE_DBUS_TEST_RUNNER)
813 endif (LOCATION_SERVICE_ENABLE_GEOCLUE_PROVIDERS)
814
815+LOCATION_SERVICE_ADD_TEST(remote_providerd_test remote_providerd_test.cpp)
816+
817 LOCATION_SERVICE_ADD_TEST(remote_provider_test remote_provider_test.cpp)
818 LOCATION_SERVICE_ADD_TEST(espoo_provider_test espoo_provider_test.cpp)
819
820=== modified file 'tests/remote_provider_test.cpp'
821--- tests/remote_provider_test.cpp 2014-09-17 13:26:40 +0000
822+++ tests/remote_provider_test.cpp 2014-09-17 13:26:40 +0000
823@@ -388,6 +388,8 @@
824
825 bus->stop();
826
827+ std::cout << "Stopped the bus" << std::endl;
828+
829 if (worker.joinable())
830 worker.join();
831
832@@ -395,7 +397,9 @@
833 core::posix::exit::Status::success;
834 }, core::posix::StandardStream::empty);
835
836+ std::cout << "Waiting for stub to finish." << std::endl;
837 EXPECT_TRUE(did_finish_successfully(stub.wait_for(core::posix::wait::Flags::untraced)));
838+ std::cout << "Shutting down skeleton." << std::endl;
839 skeleton.send_signal_or_throw(core::posix::Signal::sig_term);
840 EXPECT_TRUE(did_finish_successfully(skeleton.wait_for(core::posix::wait::Flags::untraced)));
841 }
842
843=== added file 'tests/remote_providerd_test.cpp'
844--- tests/remote_providerd_test.cpp 1970-01-01 00:00:00 +0000
845+++ tests/remote_providerd_test.cpp 2014-09-17 13:26:40 +0000
846@@ -0,0 +1,194 @@
847+/*
848+ * Copyright © 2014 Canonical Ltd.
849+ *
850+ * This program is free software: you can redistribute it and/or modify it
851+ * under the terms of the GNU Lesser General Public License version 3,
852+ * as published by the Free Software Foundation.
853+ *
854+ * This program is distributed in the hope that it will be useful,
855+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
856+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
857+ * GNU Lesser General Public License for more details.
858+ *
859+ * You should have received a copy of the GNU Lesser General Public License
860+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
861+ *
862+ * Authored by: Thomas Voß <thomas.voss@canonical.com>
863+ */
864+
865+#include <com/ubuntu/location/service/daemon.h>
866+#include <com/ubuntu/location/service/provider_daemon.h>
867+
868+#include <com/ubuntu/location/service/stub.h>
869+
870+#include <com/ubuntu/location/position.h>
871+#include <com/ubuntu/location/update.h>
872+
873+#include <core/dbus/fixture.h>
874+
875+#include <core/dbus/asio/executor.h>
876+
877+#include <core/posix/fork.h>
878+
879+#include <gmock/gmock.h>
880+
881+namespace location = com::ubuntu::location;
882+
883+namespace
884+{
885+::testing::AssertionResult did_finish_successfully(const core::posix::wait::Result& result)
886+{
887+ if (result.status != core::posix::wait::Result::Status::exited)
888+ return ::testing::AssertionFailure() << "Process did not exit, but: " << (int)result.status;
889+ if (result.detail.if_exited.status != core::posix::exit::Status::success)
890+ return ::testing::AssertionFailure() << "Process did exit with failure.";
891+
892+ return ::testing::AssertionSuccess();
893+}
894+
895+struct MockEventReceiver
896+{
897+ MOCK_METHOD1(position_update_received, void(const location::Update<location::Position>&));
898+ MOCK_METHOD1(heading_update_received, void(const location::Update<location::Heading>&));
899+ MOCK_METHOD1(velocity_update_received, void(const location::Update<location::Velocity>&));
900+};
901+
902+struct RemoteProviderdTest : public core::dbus::testing::Fixture
903+{
904+
905+};
906+}
907+
908+TEST_F(RemoteProviderdTest, AClientReceivesUpdatesFromAnOutOfProcessProvider)
909+{
910+ auto oopp = core::posix::fork([this]()
911+ {
912+ auto bus = session_bus();
913+ bus->install_executor(core::dbus::asio::make_executor(bus));
914+
915+ const char* argv[] =
916+ {
917+ "--bus", "session", // 2
918+ "--service-name", "com.ubuntu.location.providers.Dummy", // 4
919+ "--service-path", "/com/ubuntu/location/providers/Dummy", // 6
920+ "--provider", "dummy::Provider" // 8
921+ };
922+
923+ auto dbus_connection_factory = [bus](core::dbus::WellKnownBus)
924+ {
925+ return bus;
926+ };
927+
928+ return static_cast<core::posix::exit::Status>(
929+ location::service::ProviderDaemon::main(
930+ location::service::ProviderDaemon::Configuration::from_command_line_args(
931+ 8, argv, dbus_connection_factory)));
932+ }, core::posix::StandardStream::empty);
933+
934+ std::this_thread::sleep_for(std::chrono::milliseconds{250});
935+
936+ auto service = core::posix::fork([this]()
937+ {
938+ core::posix::this_process::env::set_or_throw(
939+ "TRUST_STORE_PERMISSION_MANAGER_IS_RUNNING_UNDER_TESTING",
940+ "1");
941+
942+ const char* argv[] =
943+ {
944+ "--bus", "session", // 2
945+ "--provider", "remote::Provider", // 4
946+ "--remote::Provider::bus=session_with_address_from_env", // 5
947+ "--remote::Provider::name=com.ubuntu.location.providers.Dummy", // 6
948+ "--remote::Provider::path=/com/ubuntu/location/providers/Dummy" // 7
949+ };
950+
951+ // The daemon instance requires two bus instances.
952+ auto dbus_connection_factory = [this](core::dbus::WellKnownBus)
953+ {
954+ return session_bus();
955+ };
956+
957+ return static_cast<core::posix::exit::Status>(
958+ location::service::Daemon::main(
959+ location::service::Daemon::Configuration::from_command_line_args(
960+ 7, argv, dbus_connection_factory)));
961+ }, core::posix::StandardStream::empty);
962+
963+ std::this_thread::sleep_for(std::chrono::milliseconds{250});
964+
965+ auto client = core::posix::fork([this]()
966+ {
967+ using namespace ::testing;
968+
969+ auto trap = core::posix::trap_signals_for_all_subsequent_threads(
970+ {
971+ core::posix::Signal::sig_term,
972+ core::posix::Signal::sig_int
973+ });
974+
975+ trap->signal_raised().connect([trap](const core::posix::Signal&)
976+ {
977+ trap->stop();
978+ });
979+
980+ auto bus = session_bus();
981+ bus->install_executor(core::dbus::asio::make_executor(bus));
982+
983+ std::thread worker
984+ {
985+ [bus]() { bus->run(); }
986+ };
987+
988+ MockEventReceiver receiver;
989+ EXPECT_CALL(receiver, position_update_received(_)).Times(AtLeast(1));
990+ EXPECT_CALL(receiver, heading_update_received(_)).Times(AtLeast(1));
991+ EXPECT_CALL(receiver, velocity_update_received(_)).Times(AtLeast(1));
992+
993+ com::ubuntu::location::service::Stub service{bus};
994+
995+ auto session = service.create_session_for_criteria(location::Criteria{});
996+
997+ session->updates().position.changed().connect([&receiver](location::Update<location::Position> pos)
998+ {
999+ receiver.position_update_received(pos);
1000+ });
1001+
1002+ session->updates().heading.changed().connect([&receiver](location::Update<location::Heading> heading)
1003+ {
1004+ receiver.heading_update_received(heading);
1005+ });
1006+
1007+ session->updates().velocity.changed().connect([&receiver](location::Update<location::Velocity> velocity)
1008+ {
1009+ receiver.velocity_update_received(velocity);
1010+ });
1011+
1012+ session->updates().position_status = location::service::session::Interface::Updates::Status::enabled;
1013+ session->updates().velocity_status = location::service::session::Interface::Updates::Status::enabled;
1014+ session->updates().heading_status = location::service::session::Interface::Updates::Status::enabled;
1015+
1016+ trap->run();
1017+
1018+ bus->stop();
1019+
1020+ if (worker.joinable())
1021+ worker.join();
1022+
1023+ return ::testing::Test::HasFailure() ? core::posix::exit::Status::failure :
1024+ core::posix::exit::Status::success;
1025+ }, core::posix::StandardStream::empty);
1026+
1027+ std::this_thread::sleep_for(std::chrono::milliseconds{4000});
1028+
1029+ std::cout << "Shutting down client" << std::endl;
1030+ client.send_signal_or_throw(core::posix::Signal::sig_term);
1031+ EXPECT_TRUE(did_finish_successfully(client.wait_for(core::posix::wait::Flags::untraced)));
1032+
1033+ std::cout << "Shutting down service" << std::endl;
1034+ service.send_signal_or_throw(core::posix::Signal::sig_term);
1035+ EXPECT_TRUE(did_finish_successfully(service.wait_for(core::posix::wait::Flags::untraced)));
1036+
1037+ std::cout << "Shutting down oopp" << std::endl;
1038+ oopp.send_signal_or_throw(core::posix::Signal::sig_term);
1039+ EXPECT_TRUE(did_finish_successfully(oopp.wait_for(core::posix::wait::Flags::untraced)));
1040+}

Subscribers

People subscribed via source and target branches