blob: 887b187218bc6d15a93989a728785bf805e1c093 [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>
Eric Shienbrood3e20a232012-02-16 11:35:56 -050010#include <base/stl_util.h>
David Rochbergfa1d31d2012-03-20 10:38:07 -040011#include <mm/mm-modem.h>
Ben Chanf6120e92012-06-28 18:56:17 -070012#include <ModemManager/ModemManager-names.h>
Darin Petkov887f2982011-07-14 16:10:17 -070013
Eric Shienbrood9a245532012-03-07 14:20:39 -050014#include "shill/error.h"
Christopher Wileyb691efd2012-08-09 13:51:51 -070015#include "shill/logging.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
143ModemManagerClassic::~ModemManagerClassic() {}
144
145void ModemManagerClassic::Connect(const string &supplied_owner) {
146 ModemManager::Connect(supplied_owner);
147 proxy_.reset(proxy_factory()->CreateModemManagerProxy(this, path(), owner()));
David Rochberg81030ea2012-03-02 15:44:25 -0500148 // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
149 vector<DBus::Path> devices = proxy_->EnumerateDevices();
David Rochbergfa1d31d2012-03-20 10:38:07 -0400150
David Rochberg81030ea2012-03-02 15:44:25 -0500151 for (vector<DBus::Path>::const_iterator it = devices.begin();
152 it != devices.end(); ++it) {
David Rochbergfa1d31d2012-03-20 10:38:07 -0400153 AddModemClassic(*it);
David Rochberg81030ea2012-03-02 15:44:25 -0500154 }
155}
156
David Rochbergfa1d31d2012-03-20 10:38:07 -0400157void ModemManagerClassic::AddModemClassic(const string &path) {
158 if (ModemExists(path)) {
159 return;
160 }
161 shared_ptr<ModemClassic> modem(new ModemClassic(owner(),
Jason Glasgowa585fc32012-06-06 11:04:09 -0400162 service(),
David Rochbergfa1d31d2012-03-20 10:38:07 -0400163 path,
164 control_interface(),
165 dispatcher(),
166 metrics(),
167 manager(),
168 provider_db()));
169 RecordAddedModem(modem);
170 InitModemClassic(modem);
171}
172
David Rochberg81030ea2012-03-02 15:44:25 -0500173void ModemManagerClassic::Disconnect() {
174 ModemManager::Disconnect();
175 proxy_.reset();
176}
177
David Rochbergfa1d31d2012-03-20 10:38:07 -0400178void ModemManagerClassic::InitModemClassic(shared_ptr<ModemClassic> modem) {
179 // TODO(rochberg): Switch to asynchronous calls (crosbug.com/17583).
180 if (modem == NULL) {
181 return;
182 }
183
184 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
Jason Glasgow9c09e362012-04-18 15:16:29 -0400185 proxy_factory()->CreateDBusPropertiesProxy(modem->path(),
David Rochbergfa1d31d2012-03-20 10:38:07 -0400186 modem->owner()));
187 DBusPropertiesMap properties =
188 properties_proxy->GetAll(MM_MODEM_INTERFACE);
189
190 modem->CreateDeviceClassic(properties);
David Rochberg81030ea2012-03-02 15:44:25 -0500191}
192
David Rochbergfa1d31d2012-03-20 10:38:07 -0400193void ModemManagerClassic::OnDeviceAdded(const string &path) {
194 AddModemClassic(path);
195}
196
197void ModemManagerClassic::OnDeviceRemoved(const string &path) {
198 RemoveModem(path);
199}
David Rochberg7cb06f62012-03-05 11:23:44 -0500200
201ModemManager1::ModemManager1(const string &service,
202 const string &path,
203 ControlInterface *control_interface,
204 EventDispatcher *dispatcher,
205 Metrics *metrics,
206 Manager *manager,
207 GLib *glib,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500208 mobile_provider_db *provider_db)
209 : ModemManager(service,
210 path,
211 control_interface,
212 dispatcher,
213 metrics,
214 manager,
215 glib,
216 provider_db),
217 weak_ptr_factory_(this) {}
David Rochberg7cb06f62012-03-05 11:23:44 -0500218
219ModemManager1::~ModemManager1() {}
220
221void ModemManager1::Connect(const string &supplied_owner) {
222 ModemManager::Connect(supplied_owner);
223 proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500224 proxy_factory()->CreateDBusObjectManagerProxy(path(), owner()));
225 proxy_->set_interfaces_added_callback(
226 Bind(&ModemManager1::OnInterfacesAddedSignal,
227 weak_ptr_factory_.GetWeakPtr()));
228 proxy_->set_interfaces_removed_callback(
229 Bind(&ModemManager1::OnInterfacesRemovedSignal,
230 weak_ptr_factory_.GetWeakPtr()));
David Rochberg7cb06f62012-03-05 11:23:44 -0500231
232 // TODO(rochberg): Make global kDBusDefaultTimeout and use it here
Eric Shienbrood9a245532012-03-07 14:20:39 -0500233 Error error;
234 proxy_->GetManagedObjects(&error,
235 Bind(&ModemManager1::OnGetManagedObjectsReply,
236 weak_ptr_factory_.GetWeakPtr()),
237 5000);
David Rochberg7cb06f62012-03-05 11:23:44 -0500238}
239
240void ModemManager1::Disconnect() {
241 ModemManager::Disconnect();
242 proxy_.reset();
243}
244
David Rochbergfa1d31d2012-03-20 10:38:07 -0400245void ModemManager1::AddModem1(const string &path,
246 const DBusInterfaceToProperties &i_to_p) {
247 if (ModemExists(path)) {
248 return;
249 }
250 shared_ptr<Modem1> modem1(new Modem1(owner(),
Jason Glasgowa585fc32012-06-06 11:04:09 -0400251 service(),
David Rochbergfa1d31d2012-03-20 10:38:07 -0400252 path,
253 control_interface(),
254 dispatcher(),
255 metrics(),
256 manager(),
257 provider_db()));
258 RecordAddedModem(modem1);
259 InitModem1(modem1, i_to_p);
260}
261
262void ModemManager1::InitModem1(shared_ptr<Modem1> modem,
263 const DBusInterfaceToProperties &i_to_p) {
264 if (modem == NULL) {
265 return;
266 }
267 modem->CreateDeviceMM1(i_to_p);
David Rochberg7cb06f62012-03-05 11:23:44 -0500268}
269
Eric Shienbrood9a245532012-03-07 14:20:39 -0500270// signal methods
271// Also called by OnGetManagedObjectsReply
272void ModemManager1::OnInterfacesAddedSignal(
David Rochberg7cb06f62012-03-05 11:23:44 -0500273 const ::DBus::Path &object_path,
274 const DBusInterfaceToProperties &interface_to_properties) {
David Rochbergfa1d31d2012-03-20 10:38:07 -0400275 if (ContainsKey(interface_to_properties, MM_DBUS_INTERFACE_MODEM)) {
276 AddModem1(object_path, interface_to_properties);
David Rochberg7cb06f62012-03-05 11:23:44 -0500277 } else {
278 LOG(ERROR) << "Interfaces added, but not modem interface.";
279 }
280}
281
Eric Shienbrood9a245532012-03-07 14:20:39 -0500282void ModemManager1::OnInterfacesRemovedSignal(
David Rochberg7cb06f62012-03-05 11:23:44 -0500283 const ::DBus::Path &object_path,
284 const vector<string> &interfaces) {
285 LOG(INFO) << "MM1: Removing interfaces from " << object_path;
286 if (find(interfaces.begin(),
287 interfaces.end(),
David Rochbergfa1d31d2012-03-20 10:38:07 -0400288 MM_DBUS_INTERFACE_MODEM) != interfaces.end()) {
David Rochberg7cb06f62012-03-05 11:23:44 -0500289 RemoveModem(object_path);
290 } else {
291 // In theory, a modem could drop, say, 3GPP, but not CDMA. In
292 // practice, we don't expect this
293 LOG(ERROR) << "Interfaces removed, but not modem interface";
294 }
295}
296
297// DBusObjectManagerProxy async method call
Eric Shienbrood9a245532012-03-07 14:20:39 -0500298void ModemManager1::OnGetManagedObjectsReply(
David Rochberg7cb06f62012-03-05 11:23:44 -0500299 const DBusObjectsWithProperties &objects,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500300 const Error &error) {
301 if (error.IsSuccess()) {
302 DBusObjectsWithProperties::const_iterator m;
303 for (m = objects.begin(); m != objects.end(); ++m) {
304 OnInterfacesAddedSignal(m->first, m->second);
305 }
David Rochberg7cb06f62012-03-05 11:23:44 -0500306 }
307}
308
Darin Petkov887f2982011-07-14 16:10:17 -0700309} // namespace shill