| // Copyright 2017 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 "modemfwd/logging.h" |
| #include "modemfwd/modem_tracker.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/bind.h> |
| #include <brillo/variant_dictionary.h> |
| #include <chromeos/dbus/service_constants.h> |
| |
| namespace modemfwd { |
| |
| namespace { |
| |
| void OnSignalConnected(const std::string& interface_name, |
| const std::string& signal_name, |
| bool success) { |
| DVLOG(1) << (success ? "Connected" : "Failed to connect") << " to signal " |
| << signal_name << " of " << interface_name; |
| } |
| |
| } // namespace |
| |
| ModemTracker::ModemTracker( |
| scoped_refptr<dbus::Bus> bus, |
| const OnModemCarrierIdReadyCallback& on_modem_carrier_id_ready_callback, |
| const OnModemDeviceSeenCallback& on_modem_device_seen_callback) |
| : bus_(bus), |
| shill_proxy_(new org::chromium::flimflam::ManagerProxy(bus)), |
| on_modem_carrier_id_ready_callback_(on_modem_carrier_id_ready_callback), |
| on_modem_device_seen_callback_(on_modem_device_seen_callback), |
| weak_ptr_factory_(this) { |
| shill_proxy_->GetObjectProxy()->WaitForServiceToBeAvailable(base::Bind( |
| &ModemTracker::OnServiceAvailable, weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void ModemTracker::OnServiceAvailable(bool available) { |
| if (!available) { |
| LOG(WARNING) << "shill disappeared"; |
| modem_objects_.clear(); |
| return; |
| } |
| |
| shill_proxy_->RegisterPropertyChangedSignalHandler( |
| base::Bind(&ModemTracker::OnManagerPropertyChanged, |
| weak_ptr_factory_.GetWeakPtr()), |
| base::Bind(&OnSignalConnected)); |
| |
| brillo::ErrorPtr error; |
| brillo::VariantDictionary properties; |
| if (!shill_proxy_->GetProperties(&properties, &error)) { |
| LOG(ERROR) << "Could not get property list from shill: " |
| << error->GetMessage(); |
| return; |
| } |
| |
| OnDeviceListChanged(properties[shill::kDevicesProperty] |
| .TryGet<std::vector<dbus::ObjectPath>>()); |
| } |
| |
| void ModemTracker::OnManagerPropertyChanged(const std::string& property_name, |
| const brillo::Any& property_value) { |
| if (property_name == shill::kDevicesProperty) |
| OnDeviceListChanged(property_value.TryGet<std::vector<dbus::ObjectPath>>()); |
| } |
| |
| void ModemTracker::OnDevicePropertyChanged(dbus::ObjectPath device_path, |
| const std::string& property_name, |
| const brillo::Any& property_value) { |
| // Listen only for the HomeProvider change triggered by a SIM change |
| if (property_name != shill::kHomeProviderProperty) |
| return; |
| |
| auto current_carrier_id = modem_objects_.find(device_path); |
| if (current_carrier_id == modem_objects_.end()) |
| return; |
| |
| std::map<std::string, std::string> operator_info( |
| property_value.TryGet<std::map<std::string, std::string>>()); |
| std::string carrier_id = operator_info[shill::kOperatorUuidKey]; |
| if (carrier_id == current_carrier_id->second) |
| return; |
| |
| current_carrier_id->second = carrier_id; |
| |
| ELOG(INFO) << "Carrier UUID changed to [" << carrier_id << "] for device " |
| << device_path.value(); |
| |
| // No carrier info, wait for a real one to update |
| if (carrier_id.empty()) |
| return; |
| |
| // trigger the firmware update |
| auto device = |
| std::make_unique<org::chromium::flimflam::DeviceProxy>(bus_, device_path); |
| on_modem_carrier_id_ready_callback_.Run(std::move(device)); |
| } |
| |
| void ModemTracker::OnDeviceListChanged( |
| const std::vector<dbus::ObjectPath>& new_list) { |
| std::map<dbus::ObjectPath, std::string> new_modems; |
| for (const auto& device_path : new_list) { |
| if (modem_objects_.find(device_path) != modem_objects_.end()) { |
| // Keep existing devices in the new list. |
| new_modems[device_path] = modem_objects_[device_path]; |
| continue; |
| } |
| |
| // See if the modem object is of cellular type. |
| auto device = std::make_unique<org::chromium::flimflam::DeviceProxy>( |
| bus_, device_path); |
| brillo::ErrorPtr error; |
| brillo::VariantDictionary properties; |
| if (!device->GetProperties(&properties, &error)) { |
| LOG(ERROR) << "Could not get property list for device " |
| << device_path.value() << ": " << error->GetMessage(); |
| continue; |
| } |
| |
| if (properties[shill::kTypeProperty].TryGet<std::string>() != |
| shill::kTypeCellular) { |
| DVLOG(1) << "Device " << device_path.value() |
| << " is not cellular type, ignoring"; |
| continue; |
| } |
| |
| std::string device_id; |
| std::string equipment_id; |
| if (!properties[shill::kDeviceIdProperty].GetValue(&device_id) || |
| !properties[shill::kEquipmentIdProperty].GetValue(&equipment_id)) { |
| LOG(ERROR) << "Modem " << device_path.value() |
| << " has no device ID or no equipment ID, ignoring"; |
| continue; |
| } |
| on_modem_device_seen_callback_.Run(device_id, equipment_id); |
| |
| std::map<std::string, std::string> operator_info; |
| if (!properties[shill::kHomeProviderProperty].GetValue(&operator_info)) |
| continue; |
| |
| // Record the modem device with its current carrier UUID |
| std::string carrier_id = operator_info[shill::kOperatorUuidKey]; |
| new_modems[device_path] = carrier_id; |
| |
| // Listen to the Device HomeProvider property in order to detect future SIM |
| // swaps. |
| device->RegisterPropertyChangedSignalHandler( |
| base::Bind(&ModemTracker::OnDevicePropertyChanged, |
| weak_ptr_factory_.GetWeakPtr(), device_path), |
| base::Bind(&OnSignalConnected)); |
| |
| // Try to update only if we already know the carrier |
| if (!carrier_id.empty()) |
| on_modem_carrier_id_ready_callback_.Run(std::move(device)); |
| } |
| modem_objects_ = new_modems; |
| } |
| |
| } // namespace modemfwd |