Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: src/service_manager_impl.cc

Issue 6395007: cashew: gmock integration (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/cashew.git@master
Patch Set: Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/service_manager_impl.h ('k') | src/service_manager_mock.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2010, 2011 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/service_manager_impl.h"
6
7 #include <glog/logging.h>
8
9 #include "src/cashew_server.h"
10 #include "src/service.h"
11
12 namespace cashew {
13
14 // Flimflam D-Bus indentifiers
15 static const char *kFlimflamManagerName = "org.chromium.flimflam";
16 static const char *kFlimflamManagerPath = "/";
17
18 // Flimflam property names
19 static const char *kDefaultTechnologyProperty = "DefaultTechnology";
20 static const char *kServicesProperty = "Services";
21 static const char *kStateProperty = "State";
22
23 // Flimflam on-the-wire State values
24 static const char *kFlimflamStateOffline = "offline";
25 static const char *kFlimflamStateConnected = "connected";
26 static const char *kFlimflamStateOnline = "online";
27
28 // Flimflam service types
29 static const char *kTypeCellular = "cellular";
30
31 // GetFlimflamProperties retry interval
32 static const guint kSecondsPerMinute = 60;
33 static const guint kGetFlimflamPropertiesIntervalSeconds =
34 1 * kSecondsPerMinute;
35
36 ServiceManagerImpl::ServiceManagerImpl(DBus::Connection& connection, // NOLINT
37 GMainLoop * const main_loop)
38 : DBus::ObjectProxy(connection, kFlimflamManagerPath,
39 kFlimflamManagerName),
40 connection_(connection), main_loop_(CHECK_NOTNULL(main_loop)),
41 cashew_server_(NULL), default_technology_(Service::kTypeUnknown),
42 default_cellular_service_(NULL),
43 connectivity_state_(kConnectivityStateUnknown),
44 get_properties_source_id_(0), retrying_get_properties_(false) {
45 // schedule a GetProperties() call to Flimflam to init our state
46 // we'll keep trying periodically until we succeed
47 // we'll subsequently update this state by monitoring PropertyChanged signals
48 get_properties_source_id_ =
49 g_idle_add(StaticGetFlimflamPropertiesCallback, this);
50 if (get_properties_source_id_ == 0) {
51 LOG(ERROR) << "ctor: g_idle_add failed";
52 }
53 property_changed_handler_.delegate(this);
54 }
55
56 ServiceManagerImpl::~ServiceManagerImpl() {
57 DCHECK(!g_main_loop_is_running(main_loop_));
58 ClearDefaultCellularService();
59 DeleteServices(&services_);
60 if (get_properties_source_id_ != 0 &&
61 !g_source_remove(get_properties_source_id_)) {
62 DLOG(WARNING) << "dtor: g_source_remove failed";
63 }
64 }
65
66 const Service* ServiceManagerImpl::GetService(const std::string& service_path)
67 const {
68 ServiceMap::const_iterator it = services_.find(service_path);
69 if (it == services_.end()) {
70 return NULL;
71 }
72 DCHECK(it->second != NULL);
73 return static_cast<const Service *>(it->second);
74 }
75
76 void ServiceManagerImpl::SetCashewServer(CashewServer *cashew_server) {
77 DLOG(INFO) << "SetCashewServer";
78 cashew_server_ = cashew_server;
79 }
80
81 Service::Type ServiceManagerImpl::GetDefaultTechnology() const {
82 return default_technology_;
83 }
84
85 ServiceManager::ConnectivityState ServiceManagerImpl::GetConnectivityState()
86 const {
87 return connectivity_state_;
88 }
89
90 // static
91 bool ServiceManagerImpl::IsOfflineConnectivityState(
92 ServiceManager::ConnectivityState state) {
93 if (state == kConnectivityStateUnknown ||
94 state == kConnectivityStateOffline) {
95 return true;
96 }
97 return false;
98 }
99
100 // static
101 bool ServiceManagerImpl::IsOnlineConnectivityState(
102 ServiceManager::ConnectivityState state) {
103 if (state == kConnectivityStateConnected ||
104 state == kConnectivityStateOnline) {
105 return true;
106 }
107 return false;
108 }
109
110 // Flimflam Manager D-Bus Proxy methods
111
112 void ServiceManagerImpl::PropertyChanged(const std::string& property_name,
113 const DBus::Variant& new_value) {
114 DLOG(INFO) << "PropertyChanged: property_name = " << property_name;
115 // Queue a tuple representing this signal for later processing from the glib
116 // main loop. We do this to avoid libdbus-c++ deadlocks that can occur when
117 // sending a dbus message from within a dbus callback like this one.
118 PropertyChangedSignal signal(property_name, new_value);
119 property_changed_handler_.EnqueueSignal(signal);
120 }
121
122 void ServiceManagerImpl::StateChanged(const std::string& new_state_string) {
123 DLOG(INFO) << "StateChanged: new_state_string = " << new_state_string;
124 // Queue a tuple representing this signal for later processing from the glib
125 // main loop. See comments in PropertyChanged above.
126 DBus::Variant new_value;
127 new_value.writer().append_string(new_state_string.c_str());
128 // StateChanged is a special case of PropertyChanged, so we just construct a
129 // PropertyChanged signal containing the new state info
130 PropertyChangedSignal signal(kStateProperty, new_value);
131 property_changed_handler_.EnqueueSignal(signal);
132 }
133
134 // PropertyChangedDelegate methods
135
136 void ServiceManagerImpl::OnPropertyChanged(
137 const PropertyChangedHandler *handler,
138 const std::string& property_name,
139 const DBus::Variant& new_value) {
140 DCHECK(handler == &property_changed_handler_);
141 DLOG(INFO) << "OnPropertyChanged: property_name = " << property_name;
142 if (property_name == kDefaultTechnologyProperty) {
143 OnDefaultTechnologyUpdate(new_value.reader().get_string());
144 } else if (property_name == kServicesProperty) {
145 // interpret new_value as a vector of service paths
146 ServicePathList paths;
147 DBus::MessageIter reader = new_value.reader();
148 reader >> paths;
149 OnServicesUpdate(paths);
150 } else if (property_name == kStateProperty) {
151 OnStateUpdate(new_value.reader().get_string());
152 } else {
153 // we don't care about this property
154 }
155 }
156
157 // Service methods
158
159 void ServiceManagerImpl::EmitDataPlansUpdate(const Service& service) {
160 DLOG(INFO) << "EmitDataPlansUpdate: service = " << service.GetPath();
161 if (cashew_server_ == NULL) {
162 DLOG(WARNING) << "EmitDataPlansUpdate: no Cashew server";
163 return;
164 }
165 cashew_server_->EmitDataPlansUpdate(service);
166 }
167
168 // Private methods
169
170 void ServiceManagerImpl::DeleteServices(ServiceMap *service_map) {
171 DCHECK(service_map != NULL);
172 while (!service_map->empty()) {
173 const std::string& path =
174 static_cast<std::string>(service_map->begin()->first);
175 DLOG(INFO) << "DeleteServices: deleting service: " << path;
176 Service *service = static_cast<Service *>(service_map->begin()->second);
177 DCHECK(service != NULL);
178 DCHECK(service != default_cellular_service_);
179 DCHECK(*service_map == services_ || GetService(service->GetPath()) == NULL);
180 delete service;
181 service_map->erase(service_map->begin());
182 }
183 }
184
185 // static
186 gboolean ServiceManagerImpl::StaticGetFlimflamPropertiesCallback(
187 gpointer data) {
188 ServiceManagerImpl *service_manager =
189 reinterpret_cast<ServiceManagerImpl*>(data);
190 CHECK_NOTNULL(service_manager);
191 DCHECK_NE(service_manager->get_properties_source_id_, 0);
192 if (!service_manager->GetFlimflamProperties()) {
193 // call failed, so try again later
194 DLOG(WARNING) << "StaticGetFlimflamPropertiesCallback: "
195 << "GetFlimflamProperties failed, will retry in "
196 << kGetFlimflamPropertiesIntervalSeconds << " secs";
197 // if we've arrived here from our first g_idle_add call, set up a timer
198 if (!service_manager->retrying_get_properties_) {
199 guint source_id =
200 g_timeout_add_seconds(kGetFlimflamPropertiesIntervalSeconds,
201 StaticGetFlimflamPropertiesCallback,
202 service_manager);
203 service_manager->get_properties_source_id_ = source_id;
204 if (source_id == 0) {
205 LOG(ERROR) << "StaticGetFlimflamPropertiesCallback: "
206 << "g_timeout_add_seconds failed";
207 return FALSE; // get rid of old glib source and give up
208 }
209 service_manager->retrying_get_properties_ = true;
210 // get rid of our old glib source, but our new timer will call us
211 return FALSE;
212 }
213 // otherwise, our timer is already set up
214 // return TRUE to indicate that we want to be called again later
215 return TRUE;
216 }
217 service_manager->get_properties_source_id_ = 0;
218 service_manager->retrying_get_properties_ = false;
219 return FALSE; // we succeeded, so don't repeat
220 }
221
222 bool ServiceManagerImpl::GetFlimflamProperties() {
223 DLOG(INFO) << "GetFlimflamProperties";
224 PropertyMap properties;
225 // dbus-c++ throws exceptions
226 // invoke the "Existing Non-conformant Code" clause of the style guide and
227 // isolate the rest of the system from this
228 try {
229 // TODO(vlaviano): make this call asynchronous
230 properties = GetProperties();
231 } catch (DBus::Error& error) { // NOLINT
232 LOG(WARNING) << "GetFlimflamProperties: GetProperties() -> Exception: "
233 << error.name() << ": " << error.message();
234 return false;
235 } catch (...) { // NOLINT
236 LOG(WARNING) << "GetFlimflamProperties: GetProperties() -> Exception";
237 return false;
238 }
239 DLOG(INFO) << "GetFlimflamProperties: Received " << properties.size()
240 << " properties";
241
242 // grab the properties in which we're interested
243 PropertyMap::const_iterator it = properties.find(kDefaultTechnologyProperty);
244 if (it != properties.end()) {
245 const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
246 OnDefaultTechnologyUpdate(value.reader().get_string());
247 } else {
248 DLOG(WARNING) << "GetFlimflamProperties: no DefaultTechnology property";
249 }
250 it = properties.find(kServicesProperty);
251 if (it != properties.end()) {
252 const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
253 // interpret value as vector of service paths
254 ServicePathList paths;
255 DBus::MessageIter reader = value.reader();
256 reader >> paths;
257 OnServicesUpdate(paths);
258 } else {
259 DLOG(WARNING) << "GetFlimflamProperties: no Services property";
260 }
261 it = properties.find(kStateProperty);
262 if (it != properties.end()) {
263 const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
264 StateChanged(value.reader().get_string());
265 } else {
266 DLOG(WARNING) << "GetFlimflamProperties: no State property";
267 }
268 return true;
269 }
270
271 void ServiceManagerImpl::OnStateUpdate(const std::string& new_state_string) {
272 DLOG(INFO) << "OnStateUpdate: new_state = " << new_state_string;
273 ConnectivityState old_state = connectivity_state_;
274 connectivity_state_ = ConnectivityStateFromString(new_state_string);
275 // see if we're coming online or going offline
276 // NOTE: we consider "unknown" to be offline
277 if (IsOfflineConnectivityState(old_state) &&
278 IsOnlineConnectivityState(connectivity_state_)) {
279 OnFlimflamOnline();
280 } else if (IsOnlineConnectivityState(old_state) &&
281 IsOfflineConnectivityState(connectivity_state_)) {
282 OnFlimflamOffline();
283 }
284 }
285
286 void ServiceManagerImpl::OnDefaultTechnologyUpdate(
287 const std::string& default_technology) {
288 DLOG(INFO) << "OnDefaultTechnologyUpdate: default technology = "
289 << default_technology;
290 default_technology_ = Service::TypeFromString(default_technology);
291 if (default_technology_ == Service::kTypeUnknown) {
292 LOG(WARNING) << "OnDefaultTechnologyUpdate: unknown default technology: "
293 << default_technology;
294 }
295 if (default_technology_ != Service::kTypeCellular &&
296 default_cellular_service_ != NULL) {
297 // if the default technology isn't cellular and yet we think that one of
298 // our cellular services is the default service, then we need to update
299 // our view of the world.
300 ClearDefaultCellularService();
301 }
302 }
303
304 void ServiceManagerImpl::OnServicesUpdate(const ServicePathList& paths) {
305 // Remember old set of services. This is the baseline from which we will
306 // determine what has changed.
307 ServiceMap old_services = services_;
308 services_.clear();
309
310 // Flimflam service types are embedded in their path names, so we can use
311 // the pattern "/cellular_" to decide which paths are cellular services.
312 static const std::string cellular_pattern = std::string("/") + kTypeCellular
313 + "_";
314
315 // Walk paths in this update and see if they're new to us
316 DLOG(INFO) << "OnServicesUpdate: " << paths.size() << " service paths";
317 ServicePathList::const_iterator it;
318 for (it = paths.begin(); it != paths.end(); ++it) {
319 const DBus::Path& path = *it;
320
321 // We only care about cellular services
322 if (path.find(cellular_pattern) == std::string::npos) {
323 continue;
324 }
325
326 ServiceMap::iterator old_it = old_services.find(path);
327 if (old_it != old_services.end()) {
328 // service is old: move it from old_services to services_
329 Service *service = static_cast<Service *>(old_it->second);
330 DCHECK(service != NULL);
331 old_services.erase(old_it);
332 services_[path] = service;
333 } else {
334 // service is new: create a Service obj for it and add it to services_
335 OnNewService(path);
336 }
337 }
338
339 // clear default service if it failed to appear in the update and we're
340 // about to delete it
341 if (default_cellular_service_ != NULL) {
342 ServiceMap::const_iterator it =
343 old_services.find(default_cellular_service_->GetPath());
344 if (it != old_services.end()) {
345 ClearDefaultCellularService();
346 }
347 }
348
349 // services left in old_services failed to appear in the update: delete them
350 DeleteServices(&old_services);
351
352 // Flimflam always places the default service first in its list of services,
353 // so we'll take a look at the first element in the paths list and see if the
354 // default service has changed. Note that |paths| can be empty. We still want
355 // to know about this, since it means that there is no default service.
356 const DBus::Path *default_service_path = NULL;
357 if (!paths.empty()) {
358 default_service_path = &*paths.begin();
359 }
360 OnDefaultServiceUpdate(default_service_path);
361 }
362
363 void ServiceManagerImpl::OnNewService(const DBus::Path& path) {
364 DLOG(INFO) << "OnNewService: " << path;
365 DCHECK(GetService(path) == NULL);
366 Service *service = Service::NewService(this, connection_, path);
367 if (service == NULL) {
368 LOG(ERROR) << "OnNewService: couldn't create service for " << path;
369 return;
370 }
371 services_[path] = service;
372 }
373
374 void ServiceManagerImpl::OnDefaultServiceUpdate(const DBus::Path *path) {
375 DLOG(INFO) << "OnDefaultServiceUpdate: new default service = "
376 << ((path == NULL) ? "None" : *path);
377 // check if new default service path (if any) corresponds to one of our
378 // cellular services
379 Service *new_default_cellular_service = NULL;
380 if (path != NULL) {
381 new_default_cellular_service = const_cast<Service*>(GetService(*path));
382 }
383 if (new_default_cellular_service != NULL) {
384 SetDefaultCellularService(new_default_cellular_service);
385 } else {
386 ClearDefaultCellularService();
387 }
388 }
389
390 void ServiceManagerImpl::ClearDefaultCellularService() {
391 DLOG(INFO) << "ClearDefaultCellularService";
392 if (default_cellular_service_ != NULL) {
393 DCHECK(default_cellular_service_->IsDefaultService());
394 default_cellular_service_->OnDefaultServiceUpdate(false);
395 default_cellular_service_ = NULL;
396 }
397 }
398
399 void ServiceManagerImpl::SetDefaultCellularService(Service *service) {
400 DLOG(INFO) << "SetDefaultCellularService: "
401 << ((service == NULL) ? "None" : service->GetPath());
402 if (default_cellular_service_ == service) {
403 return;
404 }
405 if (default_cellular_service_ != NULL) {
406 ClearDefaultCellularService();
407 }
408 DCHECK(default_cellular_service_ == NULL);
409 if (service != NULL) {
410 DCHECK(!service->IsDefaultService());
411 service->OnDefaultServiceUpdate(true);
412 default_cellular_service_ = service;
413 }
414 }
415
416 // static
417 ServiceManager::ConnectivityState
418 ServiceManagerImpl::ConnectivityStateFromString(const std::string& state) {
419 if (state == kFlimflamStateOffline) {
420 return kConnectivityStateOffline;
421 }
422 if (state == kFlimflamStateConnected) {
423 return kConnectivityStateConnected;
424 }
425 if (state == kFlimflamStateOnline) {
426 return kConnectivityStateOnline;
427 }
428 return kConnectivityStateUnknown;
429 }
430
431 void ServiceManagerImpl::OnFlimflamOnline() {
432 DLOG(INFO) << "OnFlimflamOnline";
433 // notify our child services
434 ServiceMap::iterator it;
435 for (it = services_.begin(); it != services_.end(); ++it) {
436 Service *service = static_cast<Service*>(it->second);
437 DCHECK(service != NULL);
438 service->OnFlimflamOnline();
439 }
440 }
441
442 void ServiceManagerImpl::OnFlimflamOffline() {
443 DLOG(INFO) << "OnFlimflamOffline";
444 // notify our child services
445 ServiceMap::iterator it;
446 for (it = services_.begin(); it != services_.end(); ++it) {
447 Service *service = static_cast<Service*>(it->second);
448 DCHECK(service != NULL);
449 service->OnFlimflamOffline();
450 }
451 }
452
453 } // namespace cashew
OLDNEW
« no previous file with comments | « src/service_manager_impl.h ('k') | src/service_manager_mock.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698