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

Side by Side Diff: src/service_manager.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.h ('k') | src/service_manager_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/service_manager.h" 5 #include "src/service_manager.h"
6 6
7 #include <glog/logging.h> 7 #include <glog/logging.h>
8 8
9 #include "src/cashew_server.h" 9 #include "src/service_manager_impl.h"
10 #include "src/service.h"
11 10
12 namespace cashew { 11 namespace cashew {
13 12
14 // Flimflam D-Bus indentifiers 13 // static
15 static const char *kFlimflamManagerName = "org.chromium.flimflam"; 14 bool ServiceManager::IsOfflineConnectivityState(ConnectivityState state) {
16 static const char *kFlimflamManagerPath = "/"; 15 return ServiceManagerImpl::IsOfflineConnectivityState(state);
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 ServiceManager::ServiceManager(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 ServiceManager::~ServiceManager() {
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* ServiceManager::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 ServiceManager::SetCashewServer(CashewServer *cashew_server) {
77 DLOG(INFO) << "SetCashewServer";
78 cashew_server_ = cashew_server;
79 }
80
81 Service::Type ServiceManager::GetDefaultTechnology() const {
82 return default_technology_;
83 }
84
85 ServiceManager::ConnectivityState ServiceManager::GetConnectivityState()
86 const {
87 return connectivity_state_;
88 } 16 }
89 17
90 // static 18 // static
91 bool ServiceManager::IsOfflineConnectivityState( 19 bool ServiceManager::IsOnlineConnectivityState(ConnectivityState state) {
92 ServiceManager::ConnectivityState state) { 20 return ServiceManagerImpl::IsOnlineConnectivityState(state);
93 if (state == kConnectivityStateUnknown ||
94 state == kConnectivityStateOffline) {
95 return true;
96 }
97 return false;
98 } 21 }
99 22
100 // static 23 // static
101 bool ServiceManager::IsOnlineConnectivityState( 24 ServiceManager* ServiceManager::NewServiceManager(
102 ServiceManager::ConnectivityState state) { 25 DBus::Connection& connection, // NOLINT
103 if (state == kConnectivityStateConnected || 26 GMainLoop * const main_loop) {
104 state == kConnectivityStateOnline) { 27 return new(std::nothrow) ServiceManagerImpl(connection, main_loop);
105 return true;
106 }
107 return false;
108 }
109
110 // Flimflam Manager D-Bus Proxy methods
111
112 void ServiceManager::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 ServiceManager::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 ServiceManager::OnPropertyChanged(const PropertyChangedHandler *handler,
137 const std::string& property_name,
138 const DBus::Variant& new_value) {
139 DCHECK(handler == &property_changed_handler_);
140 DLOG(INFO) << "OnPropertyChanged: property_name = " << property_name;
141 if (property_name == kDefaultTechnologyProperty) {
142 OnDefaultTechnologyUpdate(new_value.reader().get_string());
143 } else if (property_name == kServicesProperty) {
144 // interpret new_value as a vector of service paths
145 ServicePathList paths;
146 DBus::MessageIter reader = new_value.reader();
147 reader >> paths;
148 OnServicesUpdate(paths);
149 } else if (property_name == kStateProperty) {
150 OnStateUpdate(new_value.reader().get_string());
151 } else {
152 // we don't care about this property
153 }
154 }
155
156 // Service methods
157
158 void ServiceManager::EmitDataPlansUpdate(const Service& service) {
159 DLOG(INFO) << "EmitDataPlansUpdate: service = " << service.GetPath();
160 if (cashew_server_ == NULL) {
161 DLOG(WARNING) << "EmitDataPlansUpdate: no Cashew server";
162 return;
163 }
164 cashew_server_->EmitDataPlansUpdate(service);
165 }
166
167 // glib integration interface
168
169 guint ServiceManager::GetGetPropertiesSourceId() const {
170 return get_properties_source_id_;
171 }
172
173 void ServiceManager::SetGetPropertiesSourceId(guint source_id) {
174 get_properties_source_id_ = source_id;
175 }
176
177 bool ServiceManager::RetryingGetProperties() const {
178 return retrying_get_properties_;
179 }
180
181 void ServiceManager::OnRetryingGetProperties(bool retrying) {
182 retrying_get_properties_ = retrying;
183 }
184
185 // Private methods
186
187 void ServiceManager::DeleteServices(ServiceMap *service_map) {
188 DCHECK(service_map != NULL);
189 while (!service_map->empty()) {
190 const std::string& path =
191 static_cast<std::string>(service_map->begin()->first);
192 DLOG(INFO) << "DeleteServices: deleting service: " << path;
193 Service *service = static_cast<Service *>(service_map->begin()->second);
194 DCHECK(service != NULL);
195 DCHECK(service != default_cellular_service_);
196 DCHECK(*service_map == services_ || GetService(service->GetPath()) == NULL);
197 delete service;
198 service_map->erase(service_map->begin());
199 }
200 }
201
202 // static
203 gboolean ServiceManager::StaticGetFlimflamPropertiesCallback(gpointer data) {
204 ServiceManager *service_manager = reinterpret_cast<ServiceManager*>(data);
205 CHECK_NOTNULL(service_manager);
206 DCHECK_NE(service_manager->GetGetPropertiesSourceId(), 0);
207 if (!service_manager->GetFlimflamProperties()) {
208 // call failed, so try again later
209 DLOG(WARNING) << "StaticGetFlimflamPropertiesCallback: "
210 << "GetFlimflamProperties failed, will retry in "
211 << kGetFlimflamPropertiesIntervalSeconds << " secs";
212 // if we've arrived here from our first g_idle_add call, set up a timer
213 if (!service_manager->RetryingGetProperties()) {
214 guint source_id =
215 g_timeout_add_seconds(kGetFlimflamPropertiesIntervalSeconds,
216 StaticGetFlimflamPropertiesCallback,
217 service_manager);
218 service_manager->SetGetPropertiesSourceId(source_id);
219 if (source_id == 0) {
220 LOG(ERROR) << "StaticGetFlimflamPropertiesCallback: "
221 << "g_timeout_add_seconds failed";
222 return FALSE; // get rid of old glib source and give up
223 }
224 service_manager->OnRetryingGetProperties(true);
225 // get rid of our old glib source, but our new timer will call us
226 return FALSE;
227 }
228 // otherwise, our timer is already set up
229 // return TRUE to indicate that we want to be called again later
230 return TRUE;
231 }
232 service_manager->SetGetPropertiesSourceId(0);
233 service_manager->OnRetryingGetProperties(false);
234 return FALSE; // we succeeded, so don't repeat
235 }
236
237 bool ServiceManager::GetFlimflamProperties() {
238 DLOG(INFO) << "GetFlimflamProperties";
239 PropertyMap properties;
240 // dbus-c++ throws exceptions
241 // invoke the "Existing Non-conformant Code" clause of the style guide and
242 // isolate the rest of the system from this
243 try {
244 // TODO(vlaviano): make this call asynchronous
245 properties = GetProperties();
246 } catch (DBus::Error& error) { // NOLINT
247 LOG(WARNING) << "GetFlimflamProperties: GetProperties() -> Exception: "
248 << error.name() << ": " << error.message();
249 return false;
250 } catch (...) { // NOLINT
251 LOG(WARNING) << "GetFlimflamProperties: GetProperties() -> Exception";
252 return false;
253 }
254 DLOG(INFO) << "GetFlimflamProperties: Received " << properties.size()
255 << " properties";
256
257 // grab the properties in which we're interested
258 PropertyMap::const_iterator it = properties.find(kDefaultTechnologyProperty);
259 if (it != properties.end()) {
260 const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
261 OnDefaultTechnologyUpdate(value.reader().get_string());
262 } else {
263 DLOG(WARNING) << "GetFlimflamProperties: no DefaultTechnology property";
264 }
265 it = properties.find(kServicesProperty);
266 if (it != properties.end()) {
267 const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
268 // interpret value as vector of service paths
269 ServicePathList paths;
270 DBus::MessageIter reader = value.reader();
271 reader >> paths;
272 OnServicesUpdate(paths);
273 } else {
274 DLOG(WARNING) << "GetFlimflamProperties: no Services property";
275 }
276 it = properties.find(kStateProperty);
277 if (it != properties.end()) {
278 const DBus::Variant& value = static_cast<DBus::Variant>(it->second);
279 StateChanged(value.reader().get_string());
280 } else {
281 DLOG(WARNING) << "GetFlimflamProperties: no State property";
282 }
283 return true;
284 }
285
286 void ServiceManager::OnStateUpdate(const std::string& new_state_string) {
287 DLOG(INFO) << "OnStateUpdate: new_state = " << new_state_string;
288 ConnectivityState old_state = connectivity_state_;
289 connectivity_state_ = ConnectivityStateFromString(new_state_string);
290 // see if we're coming online or going offline
291 // NOTE: we consider "unknown" to be offline
292 if (IsOfflineConnectivityState(old_state) &&
293 IsOnlineConnectivityState(connectivity_state_)) {
294 OnFlimflamOnline();
295 } else if (IsOnlineConnectivityState(old_state) &&
296 IsOfflineConnectivityState(connectivity_state_)) {
297 OnFlimflamOffline();
298 }
299 }
300
301 void ServiceManager::OnDefaultTechnologyUpdate(
302 const std::string& default_technology) {
303 DLOG(INFO) << "OnDefaultTechnologyUpdate: default technology = "
304 << default_technology;
305 default_technology_ = Service::TypeFromString(default_technology);
306 if (default_technology_ == Service::kTypeUnknown) {
307 LOG(WARNING) << "OnDefaultTechnologyUpdate: unknown default technology: "
308 << default_technology;
309 }
310 if (default_technology_ != Service::kTypeCellular &&
311 default_cellular_service_ != NULL) {
312 // if the default technology isn't cellular and yet we think that one of
313 // our cellular services is the default service, then we need to update
314 // our view of the world.
315 ClearDefaultCellularService();
316 }
317 }
318
319 void ServiceManager::OnServicesUpdate(const ServicePathList& paths) {
320 // Remember old set of services. This is the baseline from which we will
321 // determine what has changed.
322 ServiceMap old_services = services_;
323 services_.clear();
324
325 // Flimflam service types are embedded in their path names, so we can use
326 // the pattern "/cellular_" to decide which paths are cellular services.
327 static const std::string cellular_pattern = std::string("/") + kTypeCellular
328 + "_";
329
330 // Walk paths in this update and see if they're new to us
331 DLOG(INFO) << "OnServicesUpdate: " << paths.size() << " service paths";
332 ServicePathList::const_iterator it;
333 for (it = paths.begin(); it != paths.end(); ++it) {
334 const DBus::Path& path = *it;
335
336 // We only care about cellular services
337 if (path.find(cellular_pattern) == std::string::npos) {
338 continue;
339 }
340
341 ServiceMap::iterator old_it = old_services.find(path);
342 if (old_it != old_services.end()) {
343 // service is old: move it from old_services to services_
344 Service *service = static_cast<Service *>(old_it->second);
345 DCHECK(service != NULL);
346 old_services.erase(old_it);
347 services_[path] = service;
348 } else {
349 // service is new: create a Service obj for it and add it to services_
350 OnNewService(path);
351 }
352 }
353
354 // clear default service if it failed to appear in the update and we're
355 // about to delete it
356 if (default_cellular_service_ != NULL) {
357 ServiceMap::const_iterator it =
358 old_services.find(default_cellular_service_->GetPath());
359 if (it != old_services.end()) {
360 ClearDefaultCellularService();
361 }
362 }
363
364 // services left in old_services failed to appear in the update: delete them
365 DeleteServices(&old_services);
366
367 // Flimflam always places the default service first in its list of services,
368 // so we'll take a look at the first element in the paths list and see if the
369 // default service has changed. Note that |paths| can be empty. We still want
370 // to know about this, since it means that there is no default service.
371 const DBus::Path *default_service_path = NULL;
372 if (!paths.empty()) {
373 default_service_path = &*paths.begin();
374 }
375 OnDefaultServiceUpdate(default_service_path);
376 }
377
378 void ServiceManager::OnNewService(const DBus::Path& path) {
379 DLOG(INFO) << "OnNewService: " << path;
380 DCHECK(GetService(path) == NULL);
381 Service *service = new(std::nothrow) Service(this, connection_, path);
382 if (service == NULL) {
383 LOG(ERROR) << "OnNewService: couldn't create service for " << path;
384 return;
385 }
386 services_[path] = service;
387 }
388
389 void ServiceManager::OnDefaultServiceUpdate(const DBus::Path *path) {
390 DLOG(INFO) << "OnDefaultServiceUpdate: new default service = "
391 << ((path == NULL) ? "None" : *path);
392 // check if new default service path (if any) corresponds to one of our
393 // cellular services
394 Service *new_default_cellular_service = NULL;
395 if (path != NULL) {
396 new_default_cellular_service = const_cast<Service*>(GetService(*path));
397 }
398 if (new_default_cellular_service != NULL) {
399 SetDefaultCellularService(new_default_cellular_service);
400 } else {
401 ClearDefaultCellularService();
402 }
403 }
404
405 void ServiceManager::ClearDefaultCellularService() {
406 DLOG(INFO) << "ClearDefaultCellularService";
407 if (default_cellular_service_ != NULL) {
408 DCHECK(default_cellular_service_->IsDefaultService());
409 default_cellular_service_->OnDefaultServiceUpdate(false);
410 default_cellular_service_ = NULL;
411 }
412 }
413
414 void ServiceManager::SetDefaultCellularService(Service *service) {
415 DLOG(INFO) << "SetDefaultCellularService: "
416 << ((service == NULL) ? "None" : service->GetPath());
417 if (default_cellular_service_ == service) {
418 return;
419 }
420 if (default_cellular_service_ != NULL) {
421 ClearDefaultCellularService();
422 }
423 DCHECK(default_cellular_service_ == NULL);
424 if (service != NULL) {
425 DCHECK(!service->IsDefaultService());
426 service->OnDefaultServiceUpdate(true);
427 default_cellular_service_ = service;
428 }
429 }
430
431 // static
432 ServiceManager::ConnectivityState ServiceManager::ConnectivityStateFromString(
433 const std::string& state) {
434 if (state == kFlimflamStateOffline) {
435 return kConnectivityStateOffline;
436 }
437 if (state == kFlimflamStateConnected) {
438 return kConnectivityStateConnected;
439 }
440 if (state == kFlimflamStateOnline) {
441 return kConnectivityStateOnline;
442 }
443 return kConnectivityStateUnknown;
444 }
445
446 void ServiceManager::OnFlimflamOnline() {
447 DLOG(INFO) << "OnFlimflamOnline";
448 // notify our child services
449 ServiceMap::iterator it;
450 for (it = services_.begin(); it != services_.end(); ++it) {
451 Service *service = static_cast<Service*>(it->second);
452 DCHECK(service != NULL);
453 service->OnFlimflamOnline();
454 }
455 }
456
457 void ServiceManager::OnFlimflamOffline() {
458 DLOG(INFO) << "OnFlimflamOffline";
459 // notify our child services
460 ServiceMap::iterator it;
461 for (it = services_.begin(); it != services_.end(); ++it) {
462 Service *service = static_cast<Service*>(it->second);
463 DCHECK(service != NULL);
464 service->OnFlimflamOffline();
465 }
466 } 28 }
467 29
468 } // namespace cashew 30 } // namespace cashew
OLDNEW
« no previous file with comments | « src/service_manager.h ('k') | src/service_manager_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698