Split Modem into ModemClassic and Modem1

Along the way:

  Restructure ModemManagerXxx to use the split modem classes.

  Add new mocks to limit scope of modem tests

  Change modem state enum to a neutral format and convert from MM1 and
  MMClassic to this format.

  Fix a bug where we weren't properly releasing a callback in
  DBusObjectManagerProxy.

  Add new DBus property matchers

BUG=chromium-os:27935,chromium-os:27936
TEST=unit tests

Change-Id: Ib78c7dfd9e30fe556f09a4427fd71c9d785210c9
Reviewed-on: https://gerrit.chromium.org/gerrit/19228
Commit-Ready: David Rochberg <rochberg@chromium.org>
Reviewed-by: David Rochberg <rochberg@chromium.org>
Tested-by: David Rochberg <rochberg@chromium.org>
diff --git a/modem.cc b/modem.cc
index fead592..cd5db9c 100644
--- a/modem.cc
+++ b/modem.cc
@@ -6,7 +6,6 @@
 
 #include <base/bind.h>
 #include <base/logging.h>
-#include <mm/mm-modem.h>
 
 #include "shill/cellular.h"
 #include "shill/manager.h"
@@ -25,22 +24,23 @@
 const char Modem::kPropertyState[] = "State";
 const char Modem::kPropertyType[] = "Type";
 
-Modem::Modem(const std::string &owner,
-             const std::string &path,
+Modem::Modem(const string &owner,
+             const string &path,
              ControlInterface *control_interface,
              EventDispatcher *dispatcher,
              Metrics *metrics,
              Manager *manager,
              mobile_provider_db *provider_db)
-    : proxy_factory_(ProxyFactory::GetInstance()),
-      owner_(owner),
+    : owner_(owner),
       path_(path),
       control_interface_(control_interface),
       dispatcher_(dispatcher),
       metrics_(metrics),
       manager_(manager),
       provider_db_(provider_db),
-      pending_device_info_(false) {
+      type_(Cellular::kTypeInvalid),
+      pending_device_info_(false),
+      rtnl_handler_(RTNLHandler::GetInstance()) {
   LOG(INFO) << "Modem created: " << owner << " at " << path;
 }
 
@@ -50,44 +50,43 @@
   }
 }
 
-void Modem::Init() {
-  VLOG(2) << __func__;
-  CHECK(!device_.get());
-  dbus_properties_proxy_.reset(
-      proxy_factory_->CreateDBusPropertiesProxy(this, path_, owner_));
-  CreateDevice();
-}
-
 void Modem::OnDeviceInfoAvailable(const string &link_name) {
   VLOG(2) << __func__;
   if (pending_device_info_ && link_name_ == link_name) {
+    // pending_device_info_ is only set if we've already been through
+    // CreateDeviceFromModemProperties() and saved our initial
+    // properties already
     pending_device_info_ = false;
-    CreateDevice();
+    CreateDeviceFromModemProperties(initial_modem_properties_);
   }
 }
 
-void Modem::CreateDevice() {
-  VLOG(2) << __func__;
-  // TODO(petkov): Switch to asynchronous calls (crosbug.com/17583).
-  DBusPropertiesMap properties =
-      dbus_properties_proxy_->GetAll(MM_MODEM_INTERFACE);
-  CreateDeviceFromProperties(properties);
+Cellular *Modem::ConstructCellular(const string &link_name,
+                                   const string &address,
+                                   int interface_index) {
+  LOG(INFO) << "Creating a cellular device on link " << link_name_
+            << " interface index " << interface_index << ".";
+  return new Cellular(control_interface_,
+                      dispatcher_,
+                      metrics_,
+                      manager_,
+                      link_name,
+                      address,
+                      interface_index,
+                      type_,
+                      owner_,
+                      path_,
+                      provider_db_);
 }
 
-void Modem::CreateDeviceFromProperties(const DBusPropertiesMap &properties) {
+void Modem::CreateDeviceFromModemProperties(
+    const DBusPropertiesMap &modem_properties) {
   VLOG(2) << __func__;
+
   if (device_.get()) {
     return;
   }
-
-  uint32 ip_method = kuint32max;
-  if (!DBusProperties::GetUint32(properties, kPropertyIPMethod, &ip_method) ||
-      ip_method != MM_MODEM_IP_METHOD_DHCP) {
-    LOG(ERROR) << "Unsupported IP method: " << ip_method;
-    return;
-  }
-
-  if (!DBusProperties::GetString(properties, kPropertyLinkName, &link_name_)) {
+  if (!GetLinkName(modem_properties, &link_name_)) {
     LOG(ERROR) << "Unable to create cellular device without a link name.";
     return;
   }
@@ -96,11 +95,10 @@
               << link_name_;
     return;
   }
-
   // TODO(petkov): Get the interface index from DeviceInfo, similar to the MAC
   // address below.
   int interface_index =
-      RTNLHandler::GetInstance()->GetInterfaceIndex(link_name_);
+      rtnl_handler_->GetInterfaceIndex(link_name_);
   if (interface_index < 0) {
     LOG(ERROR) << "Unable to create cellular device -- no interface index.";
     return;
@@ -109,63 +107,29 @@
   ByteString address_bytes;
   if (!manager_->device_info()->GetMACAddress(interface_index,
                                               &address_bytes)) {
+    // Save our properties, wait for OnDeviceInfoAvailable to be called.
     LOG(WARNING) << "No hardware address, device creation pending device info.";
+    initial_modem_properties_ = modem_properties;
     pending_device_info_ = true;
     return;
   }
 
-  uint32 mm_type = kuint32max;
-  Cellular::Type type;
-  DBusProperties::GetUint32(properties, kPropertyType, &mm_type);
-  switch (mm_type) {
-    case MM_MODEM_TYPE_CDMA:
-      type = Cellular::kTypeCDMA;
-      break;
-    case MM_MODEM_TYPE_GSM:
-      type = Cellular::kTypeGSM;
-      break;
-    default:
-      LOG(ERROR) << "Unsupported cellular modem type: " << mm_type;
-      return;
+  if (type_ == Cellular::kTypeUniversal) {
+    // TODO(rochberg):
+    LOG(ERROR) << "Cannot construct Cellular object for MM1";
+    return;
   }
 
-  LOG(INFO) << "Creating a cellular device on link " << link_name_
-            << " interface index " << interface_index << ".";
-  device_ = new Cellular(control_interface_,
-                         dispatcher_,
-                         metrics_,
-                         manager_,
-                         link_name_,
-                         address_bytes.HexEncode(),
-                         interface_index,
-                         type,
-                         owner_,
-                         path_,
-                         provider_db_);
+  string address = address_bytes.HexEncode();
+  device_ = ConstructCellular(link_name_, address, interface_index);
 
   uint32 modem_state = Cellular::kModemStateUnknown;
-  DBusProperties::GetUint32(properties, kPropertyState, &modem_state);
-  device_->set_modem_state(static_cast<Cellular::ModemState>(modem_state));
+  DBusProperties::GetUint32(modem_properties, kPropertyState, &modem_state);
+  device_->set_modem_state(ConvertMmToCellularModemState(modem_state));
 
   // Give the device a chance to extract any capability-specific properties.
-  device_->OnModemManagerPropertiesChanged(properties);
+  device_->OnModemManagerPropertiesChanged(modem_properties);
 
   manager_->device_info()->RegisterDevice(device_);
 }
-
-void Modem::OnDBusPropertiesChanged(
-    const string &/*interface*/,
-    const DBusPropertiesMap &/*changed_properties*/,
-    const vector<string> &/*invalidated_properties*/) {
-  // Ignored.
-}
-
-void Modem::OnModemManagerPropertiesChanged(
-    const string &/*interface*/,
-    const DBusPropertiesMap &properties) {
-  if (device_.get()) {
-    device_->OnModemManagerPropertiesChanged(properties);
-  }
-}
-
 }  // namespace shill