1//
2// Copyright (C) 2012 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "shill/cellular/modem_manager.h"
18
19#include <base/stl_util.h>
20#include <mm/mm-modem.h>
21
22#include "shill/cellular/modem.h"
23#include "shill/cellular/modem_manager_proxy_interface.h"
24#include "shill/control_interface.h"
25#include "shill/error.h"
26#include "shill/logging.h"
27#include "shill/manager.h"
28
29using std::string;
30using std::shared_ptr;
31using std::vector;
32
33namespace shill {
34
35ModemManager::ModemManager(ControlInterface* control_interface,
36                           const string& service,
37                           const string& path,
38                           ModemInfo* modem_info)
39    : control_interface_(control_interface),
40      service_(service),
41      path_(path),
42      service_connected_(false),
43      modem_info_(modem_info) {}
44
45ModemManager::~ModemManager() {}
46
47void ModemManager::Connect() {
48  // Inheriting classes call this superclass method.
49  service_connected_ = true;
50}
51
52void ModemManager::Disconnect() {
53  // Inheriting classes call this superclass method.
54  modems_.clear();
55  service_connected_ = false;
56}
57
58void ModemManager::OnAppeared() {
59  LOG(INFO) << "Modem manager " << service_ << " appeared.";
60  Connect();
61}
62
63void ModemManager::OnVanished() {
64  LOG(INFO) << "Modem manager " << service_ << " vanished.";
65  Disconnect();
66}
67
68bool ModemManager::ModemExists(const std::string& path) const {
69  CHECK(service_connected_);
70  if (ContainsKey(modems_, path)) {
71    LOG(INFO) << "ModemExists: " << path << " already exists.";
72    return true;
73  } else {
74    return false;
75  }
76}
77
78void ModemManager::RecordAddedModem(shared_ptr<Modem> modem) {
79  modems_[modem->path()] = modem;
80}
81
82void ModemManager::RemoveModem(const string& path) {
83  LOG(INFO) << "Remove modem: " << path;
84  CHECK(service_connected_);
85  modems_.erase(path);
86}
87
88void ModemManager::OnDeviceInfoAvailable(const string& link_name) {
89  for (Modems::const_iterator it = modems_.begin(); it != modems_.end(); ++it) {
90    it->second->OnDeviceInfoAvailable(link_name);
91  }
92}
93
94// ModemManagerClassic
95ModemManagerClassic::ModemManagerClassic(
96    ControlInterface* control_interface,
97    const string& service,
98    const string& path,
99    ModemInfo* modem_info)
100    : ModemManager(control_interface, service, path, modem_info) {}
101
102ModemManagerClassic::~ModemManagerClassic() {
103  Stop();
104}
105
106void ModemManagerClassic::Start() {
107  LOG(INFO) << "Start watching modem manager service: " << service();
108  CHECK(!proxy_);
109  proxy_.reset(
110      control_interface()->CreateModemManagerProxy(
111          this,
112          path(),
113          service(),
114          base::Bind(&ModemManagerClassic::OnAppeared, base::Unretained(this)),
115          base::Bind(&ModemManagerClassic::OnVanished,
116                     base::Unretained(this))));
117}
118
119void ModemManagerClassic::Stop() {
120  LOG(INFO) << "Stop watching modem manager service: " << service();
121  proxy_.reset();
122  Disconnect();
123}
124
125void ModemManagerClassic::Connect() {
126  ModemManager::Connect();
127  // TODO(petkov): Switch to asynchronous calls (crbug.com/200687).
128  vector<string> devices = proxy_->EnumerateDevices();
129
130  for (vector<string>::const_iterator it = devices.begin();
131       it != devices.end(); ++it) {
132    AddModemClassic(*it);
133  }
134}
135
136void ModemManagerClassic::AddModemClassic(const string& path) {
137  if (ModemExists(path)) {
138    return;
139  }
140  shared_ptr<ModemClassic> modem(new ModemClassic(service(),
141                                                  path,
142                                                  modem_info(),
143                                                  control_interface()));
144  RecordAddedModem(modem);
145  InitModemClassic(modem);
146}
147
148void ModemManagerClassic::Disconnect() {
149  ModemManager::Disconnect();
150}
151
152void ModemManagerClassic::InitModemClassic(shared_ptr<ModemClassic> modem) {
153  // TODO(rochberg): Switch to asynchronous calls (crbug.com/200687).
154  if (modem == nullptr) {
155    return;
156  }
157
158  std::unique_ptr<DBusPropertiesProxyInterface> properties_proxy(
159      control_interface()->CreateDBusPropertiesProxy(modem->path(),
160                                                     modem->service()));
161  KeyValueStore properties =
162      properties_proxy->GetAll(MM_MODEM_INTERFACE);
163
164  modem->CreateDeviceClassic(properties);
165}
166
167void ModemManagerClassic::OnDeviceAdded(const string& path) {
168  AddModemClassic(path);
169}
170
171void ModemManagerClassic::OnDeviceRemoved(const string& path) {
172  RemoveModem(path);
173}
174
175}  // namespace shill
176