| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "shill/cellular/modem_info.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include <chromeos/dbus/service_constants.h> |
| #include <ModemManager/ModemManager.h> |
| |
| #include "shill/cellular/dbus_objectmanager_proxy_interface.h" |
| #include "shill/cellular/modem.h" |
| #include "shill/cellular/pending_activation_store.h" |
| #include "shill/control_interface.h" |
| #include "shill/dbus/dbus_objectmanager_proxy.h" |
| #include "shill/logging.h" |
| #include "shill/manager.h" |
| |
| namespace shill { |
| |
| namespace { |
| constexpr int kGetManagedObjectsTimeout = 5000; |
| } |
| |
| ModemInfo::ModemInfo(ControlInterface* control_interface, |
| EventDispatcher* dispatcher, |
| Metrics* metrics, |
| Manager* manager) |
| : control_interface_(control_interface), |
| dispatcher_(dispatcher), |
| metrics_(metrics), |
| manager_(manager), |
| weak_ptr_factory_(this) {} |
| |
| ModemInfo::~ModemInfo() { |
| Stop(); |
| } |
| |
| void ModemInfo::Start() { |
| LOG(INFO) << "ModemInfo::Start"; |
| |
| pending_activation_store_.reset(new PendingActivationStore()); |
| pending_activation_store_->InitStorage(manager_->storage_path()); |
| |
| CHECK(!proxy_); |
| proxy_ = CreateProxy(); |
| } |
| |
| void ModemInfo::Stop() { |
| LOG(INFO) << "ModemInfo::Stop"; |
| pending_activation_store_.reset(); |
| proxy_.reset(); |
| Disconnect(); |
| } |
| |
| void ModemInfo::OnDeviceInfoAvailable(const std::string& link_name) { |
| for (const auto& modem_entry : modems_) { |
| modem_entry.second->OnDeviceInfoAvailable(link_name); |
| } |
| } |
| |
| std::unique_ptr<DBusObjectManagerProxyInterface> ModemInfo::CreateProxy() { |
| std::unique_ptr<DBusObjectManagerProxyInterface> proxy = |
| control_interface_->CreateDBusObjectManagerProxy( |
| RpcIdentifier(modemmanager::kModemManager1ServicePath), |
| modemmanager::kModemManager1ServiceName, |
| base::Bind(&ModemInfo::OnAppeared, weak_ptr_factory_.GetWeakPtr()), |
| base::Bind(&ModemInfo::OnVanished, weak_ptr_factory_.GetWeakPtr())); |
| proxy->set_interfaces_added_callback(Bind(&ModemInfo::OnInterfacesAddedSignal, |
| weak_ptr_factory_.GetWeakPtr())); |
| proxy->set_interfaces_removed_callback(Bind( |
| &ModemInfo::OnInterfacesRemovedSignal, weak_ptr_factory_.GetWeakPtr())); |
| return proxy; |
| } |
| |
| std::unique_ptr<Modem> ModemInfo::CreateModem( |
| const RpcIdentifier& path, const InterfaceToProperties& properties) { |
| auto modem = std::make_unique<Modem>(modemmanager::kModemManager1ServiceName, |
| path, this); |
| modem->CreateDeviceMM1(properties); |
| return modem; |
| } |
| |
| void ModemInfo::Connect() { |
| service_connected_ = true; |
| Error error; |
| CHECK(proxy_); |
| proxy_->GetManagedObjects(&error, |
| Bind(&ModemInfo::OnGetManagedObjectsReply, |
| weak_ptr_factory_.GetWeakPtr()), |
| kGetManagedObjectsTimeout); |
| } |
| |
| void ModemInfo::Disconnect() { |
| modems_.clear(); |
| service_connected_ = false; |
| } |
| |
| bool ModemInfo::ModemExists(const RpcIdentifier& path) const { |
| CHECK(service_connected_); |
| return base::Contains(modems_, path); |
| } |
| |
| void ModemInfo::AddModem(const RpcIdentifier& path, |
| const InterfaceToProperties& properties) { |
| if (ModemExists(path)) { |
| LOG(INFO) << "Modem " << path.value() << " already exists."; |
| return; |
| } |
| std::unique_ptr<Modem> modem = CreateModem(path, properties); |
| modems_[modem->path()] = std::move(modem); |
| } |
| |
| void ModemInfo::RemoveModem(const RpcIdentifier& path) { |
| LOG(INFO) << "Remove modem: " << path.value(); |
| CHECK(service_connected_); |
| modems_.erase(path); |
| } |
| |
| void ModemInfo::OnAppeared() { |
| LOG(INFO) << "ModemInfo::OnAppeared"; |
| Connect(); |
| } |
| |
| void ModemInfo::OnVanished() { |
| LOG(INFO) << "ModemInfo::OnVanished"; |
| Disconnect(); |
| } |
| |
| void ModemInfo::OnInterfacesAddedSignal( |
| const RpcIdentifier& object_path, const InterfaceToProperties& properties) { |
| if (!base::Contains(properties, MM_DBUS_INTERFACE_MODEM)) { |
| LOG(ERROR) << "Interfaces added, but not modem interface."; |
| return; |
| } |
| AddModem(object_path, properties); |
| } |
| |
| void ModemInfo::OnInterfacesRemovedSignal( |
| const RpcIdentifier& object_path, |
| const std::vector<std::string>& interfaces) { |
| LOG(INFO) << "ModemInfo: Removing interfaces from: " << object_path.value(); |
| if (!base::Contains(interfaces, MM_DBUS_INTERFACE_MODEM)) { |
| // In theory, a modem could drop, say, 3GPP, but not CDMA. In |
| // practice, we don't expect this. |
| LOG(ERROR) << "Interfaces removed, but not modem interface"; |
| return; |
| } |
| RemoveModem(object_path); |
| } |
| |
| void ModemInfo::OnGetManagedObjectsReply(const ObjectsWithProperties& objects, |
| const Error& error) { |
| if (!error.IsSuccess()) |
| return; |
| for (const auto& object_properties_pair : objects) { |
| OnInterfacesAddedSignal(object_properties_pair.first, |
| object_properties_pair.second); |
| } |
| } |
| |
| } // namespace shill |