blob: 54dd994ad4ba1855069e1515c0750e482f5114fa [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
Eric Shienbrood9a245532012-03-07 14:20:39 -05009#include <base/bind.h>
Darin Petkov887f2982011-07-14 16:10:17 -070010#include <base/logging.h>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050011#include <base/stl_util.h>
David Rochbergfa1d31d2012-03-20 10:38:07 -040012#include <mm/mm-modem.h>
13#include <mm/ModemManager-names.h>
Darin Petkov887f2982011-07-14 16:10:17 -070014
Eric Shienbrood9a245532012-03-07 14:20:39 -050015#include "shill/error.h"
Darin Petkov5c97ac52011-07-19 16:30:49 -070016#include "shill/modem.h"
Darin Petkovc90fe522011-07-15 13:59:47 -070017#include "shill/modem_manager_proxy.h"
18#include "shill/proxy_factory.h"
19
Eric Shienbrood9a245532012-03-07 14:20:39 -050020using base::Bind;
Darin Petkov887f2982011-07-14 16:10:17 -070021using std::string;
Darin Petkov5c97ac52011-07-19 16:30:49 -070022using std::tr1::shared_ptr;
23using std::vector;
Darin Petkov887f2982011-07-14 16:10:17 -070024
25namespace shill {
Darin Petkov887f2982011-07-14 16:10:17 -070026ModemManager::ModemManager(const string &service,
27 const string &path,
28 ControlInterface *control_interface,
29 EventDispatcher *dispatcher,
Thieu Le3426c8f2012-01-11 17:35:11 -080030 Metrics *metrics,
Darin Petkov887f2982011-07-14 16:10:17 -070031 Manager *manager,
Darin Petkov137884a2011-10-26 18:52:47 +020032 GLib *glib,
33 mobile_provider_db *provider_db)
Darin Petkovab565bb2011-10-06 02:55:51 -070034 : proxy_factory_(ProxyFactory::GetInstance()),
35 service_(service),
Darin Petkov887f2982011-07-14 16:10:17 -070036 path_(path),
37 watcher_id_(0),
38 control_interface_(control_interface),
39 dispatcher_(dispatcher),
Thieu Le3426c8f2012-01-11 17:35:11 -080040 metrics_(metrics),
Darin Petkov67d8ecf2011-07-26 16:03:30 -070041 manager_(manager),
Darin Petkov137884a2011-10-26 18:52:47 +020042 glib_(glib),
43 provider_db_(provider_db) {}
Darin Petkov887f2982011-07-14 16:10:17 -070044
45ModemManager::~ModemManager() {
46 Stop();
47}
48
49void ModemManager::Start() {
50 LOG(INFO) << "Start watching modem manager service: " << service_;
Eric Shienbroodc74cf9c2012-03-02 15:00:35 -050051 CHECK_EQ(0U, watcher_id_);
Darin Petkovc90fe522011-07-15 13:59:47 -070052 // TODO(petkov): Implement DBus name watching through dbus-c++.
Darin Petkov887f2982011-07-14 16:10:17 -070053 watcher_id_ = glib_->BusWatchName(G_BUS_TYPE_SYSTEM,
54 service_.c_str(),
55 G_BUS_NAME_WATCHER_FLAGS_NONE,
56 OnAppear,
57 OnVanish,
58 this,
59 NULL);
60}
61
62void ModemManager::Stop() {
63 LOG(INFO) << "Stop watching modem manager service: " << service_;
64 if (watcher_id_) {
65 glib_->BusUnwatchName(watcher_id_);
66 watcher_id_ = 0;
67 }
68 Disconnect();
69}
70
71void ModemManager::Connect(const string &owner) {
David Rochberg81030ea2012-03-02 15:44:25 -050072 // Inheriting classes call this superclass method.
Darin Petkov887f2982011-07-14 16:10:17 -070073 owner_ = owner;
Darin Petkov887f2982011-07-14 16:10:17 -070074}
75
76void ModemManager::Disconnect() {
David Rochberg81030ea2012-03-02 15:44:25 -050077 // Inheriting classes call this superclass method.
Darin Petkov5c97ac52011-07-19 16:30:49 -070078 modems_.clear();
Darin Petkov887f2982011-07-14 16:10:17 -070079 owner_.clear();
Darin Petkov887f2982011-07-14 16:10:17 -070080}
81
mukesh agrawal1830fa12011-09-26 14:31:40 -070082void ModemManager::OnAppear(GDBusConnection */*connection*/,
Darin Petkov887f2982011-07-14 16:10:17 -070083 const gchar *name,
84 const gchar *name_owner,
85 gpointer user_data) {
86 LOG(INFO) << "Modem manager " << name << " appeared. Owner: " << name_owner;
87 ModemManager *manager = reinterpret_cast<ModemManager *>(user_data);
88 manager->Connect(name_owner);
89}
90
mukesh agrawal1830fa12011-09-26 14:31:40 -070091void ModemManager::OnVanish(GDBusConnection */*connection*/,
Darin Petkov887f2982011-07-14 16:10:17 -070092 const gchar *name,
93 gpointer user_data) {
94 LOG(INFO) << "Modem manager " << name << " vanished.";
95 ModemManager *manager = reinterpret_cast<ModemManager *>(user_data);
96 manager->Disconnect();
97}
98
David Rochbergfa1d31d2012-03-20 10:38:07 -040099bool ModemManager::ModemExists(const std::string &path) const {
Darin Petkov5c97ac52011-07-19 16:30:49 -0700100 CHECK(!owner_.empty());
101 if (ContainsKey(modems_, path)) {
David Rochbergfa1d31d2012-03-20 10:38:07 -0400102 LOG(INFO) << "ModemExists: " << path << " already exists.";
103 return true;
104 } else {
105 return false;
Darin Petkov5c97ac52011-07-19 16:30:49 -0700106 }
David Rochbergfa1d31d2012-03-20 10:38:07 -0400107}
108
109void ModemManager::RecordAddedModem(shared_ptr<Modem> modem) {
110 modems_[modem->path()] = 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
David Rochbergfa1d31d2012-03-20 10:38:07 -0400143void ModemManagerClassic::OnDBusPropertiesChanged(
144 const string &/*interface*/,
145 const DBusPropertiesMap &/*changed_properties*/,
146 const vector<string> &/*invalidated_properties*/) {
147 // Ignored.
148}
149
150void ModemManagerClassic::OnModemManagerPropertiesChanged(
151 const string &/*interface*/,
152 const DBusPropertiesMap &properties) {
153 // Ignored
154}
155
156
David Rochberg81030ea2012-03-02 15:44:25 -0500157ModemManagerClassic::~ModemManagerClassic() {}
158
159void ModemManagerClassic::Connect(const string &supplied_owner) {
160 ModemManager::Connect(supplied_owner);
161 proxy_.reset(proxy_factory()->CreateModemManagerProxy(this, path(), owner()));
David Rochberg81030ea2012-03-02 15:44:25 -0500162 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
163 vector<DBus::Path> devices = proxy_->EnumerateDevices();
David Rochbergfa1d31d2012-03-20 10:38:07 -0400164
David Rochberg81030ea2012-03-02 15:44:25 -0500165 for (vector<DBus::Path>::const_iterator it = devices.begin();
166 it != devices.end(); ++it) {
David Rochbergfa1d31d2012-03-20 10:38:07 -0400167 AddModemClassic(*it);
David Rochberg81030ea2012-03-02 15:44:25 -0500168 }
169}
170
David Rochbergfa1d31d2012-03-20 10:38:07 -0400171void ModemManagerClassic::AddModemClassic(const string &path) {
172 if (ModemExists(path)) {
173 return;
174 }
175 shared_ptr<ModemClassic> modem(new ModemClassic(owner(),
176 path,
177 control_interface(),
178 dispatcher(),
179 metrics(),
180 manager(),
181 provider_db()));
182 RecordAddedModem(modem);
183 InitModemClassic(modem);
184}
185
David Rochberg81030ea2012-03-02 15:44:25 -0500186void ModemManagerClassic::Disconnect() {
187 ModemManager::Disconnect();
188 proxy_.reset();
189}
190
David Rochbergfa1d31d2012-03-20 10:38:07 -0400191void ModemManagerClassic::InitModemClassic(shared_ptr<ModemClassic> modem) {
192 // TODO(rochberg): Switch to asynchronous calls (crosbug.com/17583).
193 if (modem == NULL) {
194 return;
195 }
196
197 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
198 proxy_factory()->CreateDBusPropertiesProxy(this,
199 modem->path(),
200 modem->owner()));
201 DBusPropertiesMap properties =
202 properties_proxy->GetAll(MM_MODEM_INTERFACE);
203
204 modem->CreateDeviceClassic(properties);
David Rochberg81030ea2012-03-02 15:44:25 -0500205}
206
David Rochbergfa1d31d2012-03-20 10:38:07 -0400207void ModemManagerClassic::OnDeviceAdded(const string &path) {
208 AddModemClassic(path);
209}
210
211void ModemManagerClassic::OnDeviceRemoved(const string &path) {
212 RemoveModem(path);
213}
David Rochberg7cb06f62012-03-05 11:23:44 -0500214
215ModemManager1::ModemManager1(const string &service,
216 const string &path,
217 ControlInterface *control_interface,
218 EventDispatcher *dispatcher,
219 Metrics *metrics,
220 Manager *manager,
221 GLib *glib,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500222 mobile_provider_db *provider_db)
223 : ModemManager(service,
224 path,
225 control_interface,
226 dispatcher,
227 metrics,
228 manager,
229 glib,
230 provider_db),
231 weak_ptr_factory_(this) {}
David Rochberg7cb06f62012-03-05 11:23:44 -0500232
233ModemManager1::~ModemManager1() {}
234
235void ModemManager1::Connect(const string &supplied_owner) {
236 ModemManager::Connect(supplied_owner);
237 proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500238 proxy_factory()->CreateDBusObjectManagerProxy(path(), owner()));
239 proxy_->set_interfaces_added_callback(
240 Bind(&ModemManager1::OnInterfacesAddedSignal,
241 weak_ptr_factory_.GetWeakPtr()));
242 proxy_->set_interfaces_removed_callback(
243 Bind(&ModemManager1::OnInterfacesRemovedSignal,
244 weak_ptr_factory_.GetWeakPtr()));
David Rochberg7cb06f62012-03-05 11:23:44 -0500245
246 // TODO(rochberg): Make global kDBusDefaultTimeout and use it here
Eric Shienbrood9a245532012-03-07 14:20:39 -0500247 Error error;
248 proxy_->GetManagedObjects(&error,
249 Bind(&ModemManager1::OnGetManagedObjectsReply,
250 weak_ptr_factory_.GetWeakPtr()),
251 5000);
David Rochberg7cb06f62012-03-05 11:23:44 -0500252}
253
254void ModemManager1::Disconnect() {
255 ModemManager::Disconnect();
256 proxy_.reset();
257}
258
David Rochbergfa1d31d2012-03-20 10:38:07 -0400259void ModemManager1::AddModem1(const string &path,
260 const DBusInterfaceToProperties &i_to_p) {
261 if (ModemExists(path)) {
262 return;
263 }
264 shared_ptr<Modem1> modem1(new Modem1(owner(),
265 path,
266 control_interface(),
267 dispatcher(),
268 metrics(),
269 manager(),
270 provider_db()));
271 RecordAddedModem(modem1);
272 InitModem1(modem1, i_to_p);
273}
274
275void ModemManager1::InitModem1(shared_ptr<Modem1> modem,
276 const DBusInterfaceToProperties &i_to_p) {
277 if (modem == NULL) {
278 return;
279 }
280 modem->CreateDeviceMM1(i_to_p);
David Rochberg7cb06f62012-03-05 11:23:44 -0500281}
282
Eric Shienbrood9a245532012-03-07 14:20:39 -0500283// signal methods
284// Also called by OnGetManagedObjectsReply
285void ModemManager1::OnInterfacesAddedSignal(
David Rochberg7cb06f62012-03-05 11:23:44 -0500286 const ::DBus::Path &object_path,
287 const DBusInterfaceToProperties &interface_to_properties) {
David Rochbergfa1d31d2012-03-20 10:38:07 -0400288 if (ContainsKey(interface_to_properties, MM_DBUS_INTERFACE_MODEM)) {
289 AddModem1(object_path, interface_to_properties);
David Rochberg7cb06f62012-03-05 11:23:44 -0500290 } else {
291 LOG(ERROR) << "Interfaces added, but not modem interface.";
292 }
293}
294
Eric Shienbrood9a245532012-03-07 14:20:39 -0500295void ModemManager1::OnInterfacesRemovedSignal(
David Rochberg7cb06f62012-03-05 11:23:44 -0500296 const ::DBus::Path &object_path,
297 const vector<string> &interfaces) {
298 LOG(INFO) << "MM1: Removing interfaces from " << object_path;
299 if (find(interfaces.begin(),
300 interfaces.end(),
David Rochbergfa1d31d2012-03-20 10:38:07 -0400301 MM_DBUS_INTERFACE_MODEM) != interfaces.end()) {
David Rochberg7cb06f62012-03-05 11:23:44 -0500302 RemoveModem(object_path);
303 } else {
304 // In theory, a modem could drop, say, 3GPP, but not CDMA. In
305 // practice, we don't expect this
306 LOG(ERROR) << "Interfaces removed, but not modem interface";
307 }
308}
309
310// DBusObjectManagerProxy async method call
Eric Shienbrood9a245532012-03-07 14:20:39 -0500311void ModemManager1::OnGetManagedObjectsReply(
David Rochberg7cb06f62012-03-05 11:23:44 -0500312 const DBusObjectsWithProperties &objects,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500313 const Error &error) {
314 if (error.IsSuccess()) {
315 DBusObjectsWithProperties::const_iterator m;
316 for (m = objects.begin(); m != objects.end(); ++m) {
317 OnInterfacesAddedSignal(m->first, m->second);
318 }
David Rochberg7cb06f62012-03-05 11:23:44 -0500319 }
320}
321
Darin Petkov887f2982011-07-14 16:10:17 -0700322} // namespace shill