blob: 69ed70c253b6c28e687734ee0c03cba25d6be5b1 [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
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(),
162 path,
163 control_interface(),
164 dispatcher(),
165 metrics(),
166 manager(),
167 provider_db()));
168 RecordAddedModem(modem);
169 InitModemClassic(modem);
170}
171
David Rochberg81030ea2012-03-02 15:44:25 -0500172void ModemManagerClassic::Disconnect() {
173 ModemManager::Disconnect();
174 proxy_.reset();
175}
176
David Rochbergfa1d31d2012-03-20 10:38:07 -0400177void ModemManagerClassic::InitModemClassic(shared_ptr<ModemClassic> modem) {
178 // TODO(rochberg): Switch to asynchronous calls (crosbug.com/17583).
179 if (modem == NULL) {
180 return;
181 }
182
183 scoped_ptr<DBusPropertiesProxyInterface> properties_proxy(
Jason Glasgow9c09e362012-04-18 15:16:29 -0400184 proxy_factory()->CreateDBusPropertiesProxy(modem->path(),
David Rochbergfa1d31d2012-03-20 10:38:07 -0400185 modem->owner()));
186 DBusPropertiesMap properties =
187 properties_proxy->GetAll(MM_MODEM_INTERFACE);
188
189 modem->CreateDeviceClassic(properties);
David Rochberg81030ea2012-03-02 15:44:25 -0500190}
191
David Rochbergfa1d31d2012-03-20 10:38:07 -0400192void ModemManagerClassic::OnDeviceAdded(const string &path) {
193 AddModemClassic(path);
194}
195
196void ModemManagerClassic::OnDeviceRemoved(const string &path) {
197 RemoveModem(path);
198}
David Rochberg7cb06f62012-03-05 11:23:44 -0500199
200ModemManager1::ModemManager1(const string &service,
201 const string &path,
202 ControlInterface *control_interface,
203 EventDispatcher *dispatcher,
204 Metrics *metrics,
205 Manager *manager,
206 GLib *glib,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500207 mobile_provider_db *provider_db)
208 : ModemManager(service,
209 path,
210 control_interface,
211 dispatcher,
212 metrics,
213 manager,
214 glib,
215 provider_db),
216 weak_ptr_factory_(this) {}
David Rochberg7cb06f62012-03-05 11:23:44 -0500217
218ModemManager1::~ModemManager1() {}
219
220void ModemManager1::Connect(const string &supplied_owner) {
221 ModemManager::Connect(supplied_owner);
222 proxy_.reset(
Eric Shienbrood9a245532012-03-07 14:20:39 -0500223 proxy_factory()->CreateDBusObjectManagerProxy(path(), owner()));
224 proxy_->set_interfaces_added_callback(
225 Bind(&ModemManager1::OnInterfacesAddedSignal,
226 weak_ptr_factory_.GetWeakPtr()));
227 proxy_->set_interfaces_removed_callback(
228 Bind(&ModemManager1::OnInterfacesRemovedSignal,
229 weak_ptr_factory_.GetWeakPtr()));
David Rochberg7cb06f62012-03-05 11:23:44 -0500230
231 // TODO(rochberg): Make global kDBusDefaultTimeout and use it here
Eric Shienbrood9a245532012-03-07 14:20:39 -0500232 Error error;
233 proxy_->GetManagedObjects(&error,
234 Bind(&ModemManager1::OnGetManagedObjectsReply,
235 weak_ptr_factory_.GetWeakPtr()),
236 5000);
David Rochberg7cb06f62012-03-05 11:23:44 -0500237}
238
239void ModemManager1::Disconnect() {
240 ModemManager::Disconnect();
241 proxy_.reset();
242}
243
David Rochbergfa1d31d2012-03-20 10:38:07 -0400244void ModemManager1::AddModem1(const string &path,
245 const DBusInterfaceToProperties &i_to_p) {
246 if (ModemExists(path)) {
247 return;
248 }
249 shared_ptr<Modem1> modem1(new Modem1(owner(),
250 path,
251 control_interface(),
252 dispatcher(),
253 metrics(),
254 manager(),
255 provider_db()));
256 RecordAddedModem(modem1);
257 InitModem1(modem1, i_to_p);
258}
259
260void ModemManager1::InitModem1(shared_ptr<Modem1> modem,
261 const DBusInterfaceToProperties &i_to_p) {
262 if (modem == NULL) {
263 return;
264 }
265 modem->CreateDeviceMM1(i_to_p);
David Rochberg7cb06f62012-03-05 11:23:44 -0500266}
267
Eric Shienbrood9a245532012-03-07 14:20:39 -0500268// signal methods
269// Also called by OnGetManagedObjectsReply
270void ModemManager1::OnInterfacesAddedSignal(
David Rochberg7cb06f62012-03-05 11:23:44 -0500271 const ::DBus::Path &object_path,
272 const DBusInterfaceToProperties &interface_to_properties) {
David Rochbergfa1d31d2012-03-20 10:38:07 -0400273 if (ContainsKey(interface_to_properties, MM_DBUS_INTERFACE_MODEM)) {
274 AddModem1(object_path, interface_to_properties);
David Rochberg7cb06f62012-03-05 11:23:44 -0500275 } else {
276 LOG(ERROR) << "Interfaces added, but not modem interface.";
277 }
278}
279
Eric Shienbrood9a245532012-03-07 14:20:39 -0500280void ModemManager1::OnInterfacesRemovedSignal(
David Rochberg7cb06f62012-03-05 11:23:44 -0500281 const ::DBus::Path &object_path,
282 const vector<string> &interfaces) {
283 LOG(INFO) << "MM1: Removing interfaces from " << object_path;
284 if (find(interfaces.begin(),
285 interfaces.end(),
David Rochbergfa1d31d2012-03-20 10:38:07 -0400286 MM_DBUS_INTERFACE_MODEM) != interfaces.end()) {
David Rochberg7cb06f62012-03-05 11:23:44 -0500287 RemoveModem(object_path);
288 } else {
289 // In theory, a modem could drop, say, 3GPP, but not CDMA. In
290 // practice, we don't expect this
291 LOG(ERROR) << "Interfaces removed, but not modem interface";
292 }
293}
294
295// DBusObjectManagerProxy async method call
Eric Shienbrood9a245532012-03-07 14:20:39 -0500296void ModemManager1::OnGetManagedObjectsReply(
David Rochberg7cb06f62012-03-05 11:23:44 -0500297 const DBusObjectsWithProperties &objects,
Eric Shienbrood9a245532012-03-07 14:20:39 -0500298 const Error &error) {
299 if (error.IsSuccess()) {
300 DBusObjectsWithProperties::const_iterator m;
301 for (m = objects.begin(); m != objects.end(); ++m) {
302 OnInterfacesAddedSignal(m->first, m->second);
303 }
David Rochberg7cb06f62012-03-05 11:23:44 -0500304 }
305}
306
Darin Petkov887f2982011-07-14 16:10:17 -0700307} // namespace shill