blob: aef86cbda610a1be91e83451e47f12fdbcd13182 [file] [log] [blame]
Darin Petkov41c0e0a2012-01-09 16:38:53 +01001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Darin Petkov887f2982011-07-14 16:10:17 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "shill/modem_manager.h"
6
David Rochberg7cb06f62012-03-05 11:23:44 -05007#include <algorithm>
8
Darin Petkov887f2982011-07-14 16:10:17 -07009#include <base/logging.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050010#include <base/stl_util.h>
Darin Petkov887f2982011-07-14 16:10:17 -070011
David Rochberg7cb06f62012-03-05 11:23:44 -050012#include "shill/async_call_handler.h"
Darin Petkov5c97ac52011-07-19 16:30:49 -070013#include "shill/modem.h"
Darin Petkovc90fe522011-07-15 13:59:47 -070014#include "shill/modem_manager_proxy.h"
15#include "shill/proxy_factory.h"
16
Darin Petkov887f2982011-07-14 16:10:17 -070017using std::string;
Darin Petkov5c97ac52011-07-19 16:30:49 -070018using std::tr1::shared_ptr;
19using std::vector;
Darin Petkov887f2982011-07-14 16:10:17 -070020
21namespace shill {
Darin Petkov887f2982011-07-14 16:10:17 -070022ModemManager::ModemManager(const string &service,
23 const string &path,
24 ControlInterface *control_interface,
25 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080026 Metrics *metrics,
Darin Petkov887f2982011-07-14 16:10:17 -070027 Manager *manager,
Darin Petkov137884a2011-10-26 18:52:47 +020028 GLib *glib,
29 mobile_provider_db *provider_db)
Darin Petkovab565bb2011-10-06 02:55:51 -070030 : proxy_factory_(ProxyFactory::GetInstance()),
31 service_(service),
Darin Petkov887f2982011-07-14 16:10:17 -070032 path_(path),
33 watcher_id_(0),
34 control_interface_(control_interface),
35 dispatcher_(dispatcher),
Thieu Le3426c8f2012-01-11 17:35:11 -080036 metrics_(metrics),
Darin Petkov67d8ecf2011-07-26 16:03:30 -070037 manager_(manager),
Darin Petkov137884a2011-10-26 18:52:47 +020038 glib_(glib),
39 provider_db_(provider_db) {}
Darin Petkov887f2982011-07-14 16:10:17 -070040
41ModemManager::~ModemManager() {
42 Stop();
43}
44
45void ModemManager::Start() {
46 LOG(INFO) << "Start watching modem manager service: " << service_;
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -050047 CHECK_EQ(0U, watcher_id_);
Darin Petkovc90fe522011-07-15 13:59:47 -070048 // TODO(petkov): Implement DBus name watching through dbus-c++.
Darin Petkov887f2982011-07-14 16:10:17 -070049 watcher_id_ = glib_->BusWatchName(G_BUS_TYPE_SYSTEM,
50 service_.c_str(),
51 G_BUS_NAME_WATCHER_FLAGS_NONE,
52 OnAppear,
53 OnVanish,
54 this,
55 NULL);
56}
57
58void ModemManager::Stop() {
59 LOG(INFO) << "Stop watching modem manager service: " << service_;
60 if (watcher_id_) {
61 glib_->BusUnwatchName(watcher_id_);
62 watcher_id_ = 0;
63 }
64 Disconnect();
65}
66
67void ModemManager::Connect(const string &owner) {
David Rochberg81030ea2012-03-02 15:44:25 -050068 // Inheriting classes call this superclass method.
Darin Petkov887f2982011-07-14 16:10:17 -070069 owner_ = owner;
Darin Petkov887f2982011-07-14 16:10:17 -070070}
71
72void ModemManager::Disconnect() {
David Rochberg81030ea2012-03-02 15:44:25 -050073 // Inheriting classes call this superclass method.
Darin Petkov5c97ac52011-07-19 16:30:49 -070074 modems_.clear();
Darin Petkov887f2982011-07-14 16:10:17 -070075 owner_.clear();
Darin Petkov887f2982011-07-14 16:10:17 -070076}
77
mukesh agrawal1830fa12011-09-26 14:31:40 -070078void ModemManager::OnAppear(GDBusConnection */*connection*/,
Darin Petkov887f2982011-07-14 16:10:17 -070079 const gchar *name,
80 const gchar *name_owner,
81 gpointer user_data) {
82 LOG(INFO) << "Modem manager " << name << " appeared. Owner: " << name_owner;
83 ModemManager *manager = reinterpret_cast<ModemManager *>(user_data);
84 manager->Connect(name_owner);
85}
86
mukesh agrawal1830fa12011-09-26 14:31:40 -070087void ModemManager::OnVanish(GDBusConnection */*connection*/,
Darin Petkov887f2982011-07-14 16:10:17 -070088 const gchar *name,
89 gpointer user_data) {
90 LOG(INFO) << "Modem manager " << name << " vanished.";
91 ModemManager *manager = reinterpret_cast<ModemManager *>(user_data);
92 manager->Disconnect();
93}
94
Darin Petkov41c0e0a2012-01-09 16:38:53 +010095void ModemManager::AddModem(const string &path) {
Darin Petkov5c97ac52011-07-19 16:30:49 -070096 LOG(INFO) << "Add modem: " << path;
97 CHECK(!owner_.empty());
98 if (ContainsKey(modems_, path)) {
99 LOG(INFO) << "Modem already exists; ignored.";
100 return;
101 }
Darin Petkov137884a2011-10-26 18:52:47 +0200102 shared_ptr<Modem> modem(new Modem(owner_,
103 path,
104 control_interface_,
105 dispatcher_,
Thieu Le3426c8f2012-01-11 17:35:11 -0800106 metrics_,
Darin Petkov137884a2011-10-26 18:52:47 +0200107 manager_,
108 provider_db_));
Darin Petkov5c97ac52011-07-19 16:30:49 -0700109 modems_[path] = modem;
David Rochberg81030ea2012-03-02 15:44:25 -0500110 InitModem(modem);
Darin Petkov5c97ac52011-07-19 16:30:49 -0700111}
112
Darin Petkov41c0e0a2012-01-09 16:38:53 +0100113void ModemManager::RemoveModem(const string &path) {
Darin Petkov5c97ac52011-07-19 16:30:49 -0700114 LOG(INFO) << "Remove modem: " << path;
115 CHECK(!owner_.empty());
116 modems_.erase(path);
117}
118
Darin Petkov41c0e0a2012-01-09 16:38:53 +0100119void ModemManager::OnDeviceInfoAvailable(const string &link_name) {
David Rochberg81030ea2012-03-02 15:44:25 -0500120 for (Modems::const_iterator it = modems_.begin(); it != modems_.end(); ++it) {
Darin Petkov41c0e0a2012-01-09 16:38:53 +0100121 it->second->OnDeviceInfoAvailable(link_name);
122 }
123}
124
David Rochberg81030ea2012-03-02 15:44:25 -0500125// ModemManagerClassic
David Rochberg7cb06f62012-03-05 11:23:44 -0500126ModemManagerClassic::ModemManagerClassic(const string &service,
127 const string &path,
David Rochberg81030ea2012-03-02 15:44:25 -0500128 ControlInterface *control_interface,
129 EventDispatcher *dispatcher,
130 Metrics *metrics,
131 Manager *manager,
132 GLib *glib,
133 mobile_provider_db *provider_db) :
134 ModemManager(service,
135 path,
136 control_interface,
137 dispatcher,
138 metrics,
139 manager,
140 glib,
141 provider_db) {}
142
143ModemManagerClassic::~ModemManagerClassic() {}
144
145void ModemManagerClassic::Connect(const string &supplied_owner) {
146 ModemManager::Connect(supplied_owner);
147 proxy_.reset(proxy_factory()->CreateModemManagerProxy(this, path(), owner()));
148
149 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
150 vector<DBus::Path> devices = proxy_->EnumerateDevices();
151 for (vector<DBus::Path>::const_iterator it = devices.begin();
152 it != devices.end(); ++it) {
153 AddModem(*it);
154 }
155}
156
157void ModemManagerClassic::Disconnect() {
158 ModemManager::Disconnect();
159 proxy_.reset();
160}
161
162void ModemManagerClassic::InitModem(shared_ptr<Modem> modem) {
163 modem->Init();
164}
165
David Rochberg7cb06f62012-03-05 11:23:44 -0500166// ModemManager1
167const char ModemManager1::kDBusInterfaceModem[] =
168 "org.freedesktop.ModemManager1.Modem";
169
170ModemManager1::ModemManager1(const string &service,
171 const string &path,
172 ControlInterface *control_interface,
173 EventDispatcher *dispatcher,
174 Metrics *metrics,
175 Manager *manager,
176 GLib *glib,
177 mobile_provider_db *provider_db) :
178 ModemManager(service,
179 path,
180 control_interface,
181 dispatcher,
182 metrics,
183 manager,
184 glib,
185 provider_db) {}
186
187ModemManager1::~ModemManager1() {}
188
189void ModemManager1::Connect(const string &supplied_owner) {
190 ModemManager::Connect(supplied_owner);
191 proxy_.reset(
192 proxy_factory()->CreateDBusObjectManagerProxy(this, path(), owner()));
193
194 // TODO(rochberg): Make global kDBusDefaultTimeout and use it here
195 proxy_->GetManagedObjects(new AsyncCallHandler(NULL), 5000);
196}
197
198void ModemManager1::Disconnect() {
199 ModemManager::Disconnect();
200 proxy_.reset();
201}
202
203void ModemManager1::InitModem(shared_ptr<Modem> modem) {
204 LOG(ERROR) << __func__;
205}
206
207// DBusObjectManagerProxyDelegate signal methods
208// Also called by OnGetManagedObjectsCallback
209void ModemManager1::OnInterfacesAdded(
210 const ::DBus::Path &object_path,
211 const DBusInterfaceToProperties &interface_to_properties) {
212 if (ContainsKey(interface_to_properties, kDBusInterfaceModem)) {
213 AddModem(object_path);
214 } else {
215 LOG(ERROR) << "Interfaces added, but not modem interface.";
216 }
217}
218
219void ModemManager1::OnInterfacesRemoved(
220 const ::DBus::Path &object_path,
221 const vector<string> &interfaces) {
222 LOG(INFO) << "MM1: Removing interfaces from " << object_path;
223 if (find(interfaces.begin(),
224 interfaces.end(),
225 kDBusInterfaceModem) != interfaces.end()) {
226 RemoveModem(object_path);
227 } else {
228 // In theory, a modem could drop, say, 3GPP, but not CDMA. In
229 // practice, we don't expect this
230 LOG(ERROR) << "Interfaces removed, but not modem interface";
231 }
232}
233
234// DBusObjectManagerProxy async method call
235void ModemManager1::OnGetManagedObjectsCallback(
236 const DBusObjectsWithProperties &objects,
237 const Error &error,
238 AsyncCallHandler * /* call_handler */) {
239 DBusObjectsWithProperties::const_iterator m;
240 for (m = objects.begin(); m != objects.end(); ++m) {
241 OnInterfacesAdded(m->first, m->second);
242 }
243}
244
Darin Petkov887f2982011-07-14 16:10:17 -0700245} // namespace shill