shill: cellular: Obtain IMSI when a GSM device is constructed.

This CL modifies CellularCapabilityGSM to obtain the IMSI value at
construction instead of when the modem is enabled. The IMSI value is
checked by Chrome to determine if a SIM is present before the device can
be enabled.

BUG=chromium-os:31651
TEST=Tested the following:
1. Build and run unit tests.
2. Verify that Gobi and Icera modems can be enabled as follows:
   a. Configure the modem in GSM and insert a SIM with no PIN lock.
   b. Disable the cellular device from UI.
   c. Reboot the Chromebook.
   d. Enable the cellular device from UI and it works.
   e. Repeat with a PIN-locked SIM.
3. Verify that Gobi and Icera modems cannot be enabled as follows:
   a. Configure the modem in GSM with no SIM inserted.
   b. Disable the cellular device from UI.
   c. Reboot the Chromebook.
   d. Enable the cellular device from UI and it does not work.

Change-Id: Iff21f972661cedb383b9a6820fdc7ba3160fd01a
Reviewed-on: https://gerrit.chromium.org/gerrit/29313
Commit-Ready: Ben Chan <benchan@chromium.org>
Reviewed-by: Ben Chan <benchan@chromium.org>
Tested-by: Ben Chan <benchan@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 32c2ccd..a69eaa2 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -98,7 +98,8 @@
                    const string &owner,
                    const string &service,
                    const string &path,
-                   mobile_provider_db *provider_db)
+                   mobile_provider_db *provider_db,
+                   ProxyFactory *proxy_factory)
     : Device(control_interface,
              dispatcher,
              metrics,
@@ -113,6 +114,7 @@
       dbus_service_(service),
       dbus_path_(path),
       provider_db_(provider_db),
+      proxy_factory_(proxy_factory),
       allow_roaming_(false) {
   PropertyStore *store = this->mutable_store();
   // TODO(jglasgow): kDBusConnectionProperty is deprecated.
@@ -128,7 +130,7 @@
   store->RegisterConstStringmap(flimflam::kHomeProviderProperty,
                                 &home_provider_.ToDict());
   // For now, only a single capability is supported.
-  InitCapability(type, ProxyFactory::GetInstance());
+  InitCapability(type);
 
   SLOG(Cellular, 2) << "Cellular device " << this->link_name()
                     << " initialized.";
@@ -268,19 +270,19 @@
   callback.Run(error);
 }
 
-void Cellular::InitCapability(Type type, ProxyFactory *proxy_factory) {
+void Cellular::InitCapability(Type type) {
   // TODO(petkov): Consider moving capability construction into a factory that's
   // external to the Cellular class.
   SLOG(Cellular, 2) << __func__ << "(" << type << ")";
   switch (type) {
     case kTypeGSM:
-      capability_.reset(new CellularCapabilityGSM(this, proxy_factory));
+      capability_.reset(new CellularCapabilityGSM(this, proxy_factory_));
       break;
     case kTypeCDMA:
-      capability_.reset(new CellularCapabilityCDMA(this, proxy_factory));
+      capability_.reset(new CellularCapabilityCDMA(this, proxy_factory_));
       break;
     case kTypeUniversal:
-      capability_.reset(new CellularCapabilityUniversal(this, proxy_factory));
+      capability_.reset(new CellularCapabilityUniversal(this, proxy_factory_));
       break;
     default: NOTREACHED();
   }
diff --git a/cellular.h b/cellular.h
index ba59a76..2478a4b 100644
--- a/cellular.h
+++ b/cellular.h
@@ -108,7 +108,8 @@
            const std::string &owner,
            const std::string &service,
            const std::string &path,
-           mobile_provider_db *provider_db);
+           mobile_provider_db *provider_db,
+           ProxyFactory *proxy_factory);
   virtual ~Cellular();
 
   // Load configuration for the device from |storage|.
@@ -253,7 +254,7 @@
   // to the network-connected state and bring the network interface up.
   void EstablishLink();
 
-  void InitCapability(Type type, ProxyFactory *proxy_factory);
+  void InitCapability(Type type);
 
   void CreateService();
 
@@ -292,6 +293,7 @@
   const std::string dbus_path_;  // ModemManager.Modem
 
   mobile_provider_db *provider_db_;
+  ProxyFactory *proxy_factory_;
 
   CellularServiceRefPtr service_;
 
diff --git a/cellular_capability_cdma_unittest.cc b/cellular_capability_cdma_unittest.cc
index 5b2b28e..7deaf90 100644
--- a/cellular_capability_cdma_unittest.cc
+++ b/cellular_capability_cdma_unittest.cc
@@ -19,6 +19,7 @@
 #include "shill/mock_metrics.h"
 #include "shill/mock_modem_cdma_proxy.h"
 #include "shill/nice_mock_control.h"
+#include "shill/proxy_factory.h"
 
 using base::Bind;
 using base::Unretained;
@@ -44,7 +45,8 @@
                                "",
                                "",
                                "",
-                               NULL)),
+                               NULL,
+                               ProxyFactory::GetInstance())),
         proxy_(new MockModemCDMAProxy()),
         capability_(NULL) {}
 
diff --git a/cellular_capability_classic.cc b/cellular_capability_classic.cc
index 08c93c9..ad578b0 100644
--- a/cellular_capability_classic.cc
+++ b/cellular_capability_classic.cc
@@ -142,7 +142,8 @@
     return;
   }
   delete tasks;
-  callback.Run(error);
+  if (!callback.is_null())
+    callback.Run(error);
 }
 
 // always called from an async context
diff --git a/cellular_capability_classic_unittest.cc b/cellular_capability_classic_unittest.cc
index 0a12c74..f0a2ab6 100644
--- a/cellular_capability_classic_unittest.cc
+++ b/cellular_capability_classic_unittest.cc
@@ -48,6 +48,16 @@
  public:
   CellularCapabilityTest()
       : manager_(&control_, &dispatcher_, &metrics_, &glib_),
+        create_gsm_card_proxy_from_factory_(false),
+        proxy_(new MockModemProxy()),
+        simple_proxy_(new MockModemSimpleProxy()),
+        cdma_proxy_(new MockModemCDMAProxy()),
+        gsm_card_proxy_(new MockModemGSMCardProxy()),
+        gsm_network_proxy_(new MockModemGSMNetworkProxy()),
+        proxy_factory_(this),
+        capability_(NULL),
+        device_adaptor_(NULL),
+        provider_db_(NULL),
         cellular_(new Cellular(&control_,
                                &dispatcher_,
                                NULL,
@@ -59,16 +69,8 @@
                                "",
                                "",
                                "",
-                               NULL)),
-        proxy_(new MockModemProxy()),
-        simple_proxy_(new MockModemSimpleProxy()),
-        cdma_proxy_(new MockModemCDMAProxy()),
-        gsm_card_proxy_(new MockModemGSMCardProxy()),
-        gsm_network_proxy_(new MockModemGSMNetworkProxy()),
-        proxy_factory_(this),
-        capability_(NULL),
-        device_adaptor_(NULL),
-        provider_db_(NULL) {}
+                               NULL,
+                               &proxy_factory_)) {}
 
   virtual ~CellularCapabilityTest() {
     cellular_->service_ = NULL;
@@ -177,7 +179,12 @@
     virtual ModemGSMCardProxyInterface *CreateModemGSMCardProxy(
         const string &/*path*/,
         const string &/*service*/) {
-      return test_->gsm_card_proxy_.release();
+      // TODO(benchan): This code conditionally returns a NULL pointer to avoid
+      // CellularCapabilityGSM::InitProperties (and thus
+      // CellularCapabilityGSM::GetIMSI) from being called during the
+      // construction. Remove this workaround after refactoring the tests.
+      return test_->create_gsm_card_proxy_from_factory_ ?
+          test_->gsm_card_proxy_.release() : NULL;
     }
 
     virtual ModemGSMNetworkProxyInterface *CreateModemGSMNetworkProxy(
@@ -205,18 +212,22 @@
   }
 
   void SetCellularType(Cellular::Type type) {
-    cellular_->InitCapability(type, &proxy_factory_);
+    cellular_->InitCapability(type);
     capability_ = dynamic_cast<CellularCapabilityClassic *>(
         cellular_->capability_.get());
   }
 
+  void AllowCreateGSMCardProxyFromFactory() {
+    create_gsm_card_proxy_from_factory_ = true;
+  }
+
   NiceMockControl control_;
   EventDispatcher dispatcher_;
   MockMetrics metrics_;
   MockGLib glib_;
   MockManager manager_;
-  CellularRefPtr cellular_;
   MockRTNLHandler rtnl_handler_;
+  bool create_gsm_card_proxy_from_factory_;
   scoped_ptr<MockModemProxy> proxy_;
   scoped_ptr<MockModemSimpleProxy> simple_proxy_;
   scoped_ptr<MockModemCDMAProxy> cdma_proxy_;
@@ -226,6 +237,7 @@
   CellularCapabilityClassic *capability_;  // Owned by |cellular_|.
   NiceMock<DeviceMockAdaptor> *device_adaptor_;  // Owned by |cellular_|.
   mobile_provider_db *provider_db_;
+  CellularRefPtr cellular_;
 };
 
 const char CellularCapabilityTest::kTestMobileProviderDBPath[] =
diff --git a/cellular_capability_gsm.cc b/cellular_capability_gsm.cc
index bb14966..ad7b9ee 100644
--- a/cellular_capability_gsm.cc
+++ b/cellular_capability_gsm.cc
@@ -77,6 +77,22 @@
   store->RegisterConstStringmaps(flimflam::kCellularApnListProperty,
                                  &apn_list_);
   scanning_supported_ = true;
+
+  // TODO(benchan): This is a hack to initialize the GSM card proxy for GetIMSI
+  // before InitProxies is called. There are side-effects of calling InitProxies
+  // before the device is enabled. It's better to refactor InitProxies such that
+  // proxies can be created when the cellular device/capability is constructed,
+  // but callbacks for DBus signal updates are not set up until the device is
+  // enabled.
+  card_proxy_.reset(
+      proxy_factory->CreateModemGSMCardProxy(cellular->dbus_path(),
+                                             cellular->dbus_owner()));
+  // TODO(benchan): To allow unit testing using a mock proxy without further
+  // complicating the code, the test proxy factory is set up to return a NULL
+  // pointer when CellularCapabilityGSM is constructed. Refactor the code to
+  // avoid this hack.
+  if (card_proxy_.get())
+    InitProperties();
 }
 
 KeyValueStore CellularCapabilityGSM::SimLockStatusToProperty(Error */*error*/) {
@@ -102,9 +118,13 @@
 
 void CellularCapabilityGSM::InitProxies() {
   CellularCapabilityClassic::InitProxies();
-  card_proxy_.reset(
-      proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
-                                               cellular()->dbus_owner()));
+  // TODO(benchan): Remove this check after refactoring the proxy
+  // initialization.
+  if (!card_proxy_.get()) {
+    card_proxy_.reset(
+        proxy_factory()->CreateModemGSMCardProxy(cellular()->dbus_path(),
+                                                 cellular()->dbus_owner()));
+  }
   network_proxy_.reset(
       proxy_factory()->CreateModemGSMNetworkProxy(cellular()->dbus_path(),
                                                   cellular()->dbus_owner()));
@@ -119,6 +139,19 @@
            weak_ptr_factory_.GetWeakPtr()));
 }
 
+void CellularCapabilityGSM::InitProperties() {
+  CellularTaskList *tasks = new CellularTaskList();
+  ResultCallback cb_ignore_error =
+      Bind(&CellularCapabilityGSM::StepCompletedCallback,
+           weak_ptr_factory_.GetWeakPtr(), ResultCallback(), true, tasks);
+  // Chrome uses IMSI to determine if a SIM is present before allowing the
+  // modem to be enabled, so shill needs to obtain IMSI even before the device
+  // is enabled.
+  tasks->push_back(Bind(&CellularCapabilityGSM::GetIMSI,
+                        weak_ptr_factory_.GetWeakPtr(), cb_ignore_error));
+  RunNextStep(tasks);
+}
+
 void CellularCapabilityGSM::StartModem(Error *error,
                                        const ResultCallback &callback) {
   InitProxies();
diff --git a/cellular_capability_gsm.h b/cellular_capability_gsm.h
index b27f222..a495043 100644
--- a/cellular_capability_gsm.h
+++ b/cellular_capability_gsm.h
@@ -81,6 +81,11 @@
  protected:
   virtual void InitProxies();
   virtual void ReleaseProxies();
+
+  // Initializes properties, such as IMSI, which are required before the device
+  // is enabled.
+  virtual void InitProperties();
+
   virtual void UpdateStatus(const DBusPropertiesMap &properties);
 
  private:
diff --git a/cellular_capability_gsm_unittest.cc b/cellular_capability_gsm_unittest.cc
index 8460003..d8f6dae 100644
--- a/cellular_capability_gsm_unittest.cc
+++ b/cellular_capability_gsm_unittest.cc
@@ -53,7 +53,16 @@
 class CellularCapabilityGSMTest : public testing::Test {
  public:
   CellularCapabilityGSMTest()
-      : cellular_(new Cellular(&control_,
+      : create_card_proxy_from_factory_(false),
+        proxy_(new MockModemProxy()),
+        simple_proxy_(new MockModemSimpleProxy()),
+        card_proxy_(new MockModemGSMCardProxy()),
+        network_proxy_(new MockModemGSMNetworkProxy()),
+        proxy_factory_(this),
+        capability_(NULL),
+        device_adaptor_(NULL),
+        provider_db_(NULL),
+        cellular_(new Cellular(&control_,
                                &dispatcher_,
                                &metrics_,
                                NULL,
@@ -64,15 +73,8 @@
                                "",
                                "",
                                "",
-                               NULL)),
-        proxy_(new MockModemProxy()),
-        simple_proxy_(new MockModemSimpleProxy()),
-        card_proxy_(new MockModemGSMCardProxy()),
-        network_proxy_(new MockModemGSMNetworkProxy()),
-        proxy_factory_(this),
-        capability_(NULL),
-        device_adaptor_(NULL),
-        provider_db_(NULL) {}
+                               NULL,
+                               &proxy_factory_)) {}
 
   virtual ~CellularCapabilityGSMTest() {
     cellular_->service_ = NULL;
@@ -219,7 +221,12 @@
     virtual ModemGSMCardProxyInterface *CreateModemGSMCardProxy(
         const string &/*path*/,
         const string &/*service*/) {
-      return test_->card_proxy_.release();
+      // TODO(benchan): This code conditionally returns a NULL pointer to avoid
+      // CellularCapabilityGSM::InitProperties (and thus
+      // CellularCapabilityGSM::GetIMSI) from being called during the
+      // construction. Remove this workaround after refactoring the tests.
+      return test_->create_card_proxy_from_factory_ ?
+          test_->card_proxy_.release() : NULL;
     }
 
     virtual ModemGSMNetworkProxyInterface *CreateModemGSMNetworkProxy(
@@ -244,10 +251,6 @@
     capability_->network_proxy_.reset(network_proxy_.release());
   }
 
-  void SetProxyFactory() {
-    capability_->proxy_factory_ = &proxy_factory_;
-  }
-
   void SetAccessTechnology(uint32 technology) {
     capability_->access_technology_ = technology;
   }
@@ -298,13 +301,18 @@
   }
 
   void InitProxies() {
+    AllowCreateCardProxyFromFactory();
     capability_->InitProxies();
   }
 
+  void AllowCreateCardProxyFromFactory() {
+    create_card_proxy_from_factory_ = true;
+  }
+
   NiceMockControl control_;
   EventDispatcher dispatcher_;
   MockMetrics metrics_;
-  CellularRefPtr cellular_;
+  bool create_card_proxy_from_factory_;
   scoped_ptr<MockModemProxy> proxy_;
   scoped_ptr<MockModemSimpleProxy> simple_proxy_;
   scoped_ptr<MockModemGSMCardProxy> card_proxy_;
@@ -313,6 +321,7 @@
   CellularCapabilityGSM *capability_;  // Owned by |cellular_|.
   NiceMock<DeviceMockAdaptor> *device_adaptor_;  // Owned by |cellular_|.
   mobile_provider_db *provider_db_;
+  CellularRefPtr cellular_;
   ScanResultsCallback scan_callback_;  // saved for testing scan operations
 };
 
@@ -901,7 +910,7 @@
   EXPECT_CALL(*card_proxy_,
               GetMSISDN(_, _, CellularCapability::kTimeoutDefault))
       .WillOnce(Invoke(this, &CellularCapabilityGSMTest::InvokeGetMSISDN));
-  SetProxyFactory();
+  AllowCreateCardProxyFromFactory();
 
   Error error;
   capability_->StartModem(
@@ -917,7 +926,7 @@
   EXPECT_CALL(*card_proxy_,
               GetMSISDN(_, _, CellularCapability::kTimeoutDefault))
       .WillOnce(Invoke(this, &CellularCapabilityGSMTest::InvokeGetMSISDN));
-  SetProxyFactory();
+  AllowCreateCardProxyFromFactory();
 
   Error error;
   capability_->StartModem(
@@ -933,7 +942,7 @@
   EXPECT_CALL(*card_proxy_,
               GetMSISDN(_, _, CellularCapability::kTimeoutDefault))
       .WillOnce(Invoke(this, &CellularCapabilityGSMTest::InvokeGetMSISDNFail));
-  SetProxyFactory();
+  AllowCreateCardProxyFromFactory();
 
   Error error;
   capability_->StartModem(
@@ -950,7 +959,6 @@
               Connect(_, _, _, CellularCapabilityGSM::kTimeoutConnect))
        .WillOnce(Invoke(this, &CellularCapabilityGSMTest::InvokeConnectFail));
   EXPECT_CALL(*this, TestCallback(IsFailure()));
-  SetProxyFactory();
   InitProxies();
   EXPECT_FALSE(capability_->cellular()->service());
   Error error;
diff --git a/cellular_capability_universal_unittest.cc b/cellular_capability_universal_unittest.cc
index a8eb207..a696172 100644
--- a/cellular_capability_universal_unittest.cc
+++ b/cellular_capability_universal_unittest.cc
@@ -64,6 +64,16 @@
  public:
   CellularCapabilityUniversalTest()
       : manager_(&control_, &dispatcher_, &metrics_, &glib_),
+        modem_3gpp_proxy_(new mm1::MockModemModem3gppProxy()),
+        modem_cdma_proxy_(new mm1::MockModemModemCdmaProxy()),
+        modem_proxy_(new mm1::MockModemProxy()),
+        modem_simple_proxy_(new mm1::MockModemSimpleProxy()),
+        sim_proxy_(new mm1::MockSimProxy()),
+        properties_proxy_(new MockDBusPropertiesProxy()),
+        proxy_factory_(this),
+        capability_(NULL),
+        device_adaptor_(NULL),
+        provider_db_(NULL),
         cellular_(new Cellular(&control_,
                                &dispatcher_,
                                NULL,
@@ -75,21 +85,13 @@
                                "",
                                "",
                                "",
-                               NULL)),
+                               NULL,
+                               &proxy_factory_)),
         service_(new MockCellularService(&control_,
                                          &dispatcher_,
                                          &metrics_,
                                          &manager_,
-                                         cellular_)),
-        modem_3gpp_proxy_(new mm1::MockModemModem3gppProxy()),
-        modem_cdma_proxy_(new mm1::MockModemModemCdmaProxy()),
-        modem_proxy_(new mm1::MockModemProxy()),
-        modem_simple_proxy_(new mm1::MockModemSimpleProxy()),
-        sim_proxy_(new mm1::MockSimProxy()),
-        properties_proxy_(new MockDBusPropertiesProxy()),
-        proxy_factory_(this),
-        capability_(NULL),
-        device_adaptor_(NULL) {}
+                                         cellular_)) {}
 
   virtual ~CellularCapabilityUniversalTest() {
     cellular_->service_ = NULL;
@@ -100,7 +102,6 @@
   virtual void SetUp() {
     capability_ = dynamic_cast<CellularCapabilityUniversal *>(
         cellular_->capability_.get());
-    capability_->proxy_factory_ = &proxy_factory_;
     device_adaptor_ =
         dynamic_cast<NiceMock<DeviceMockAdaptor> *>(cellular_->adaptor());
     cellular_->service_ = service_;
@@ -208,8 +209,6 @@
   MockMetrics metrics_;
   MockGLib glib_;
   MockManager manager_;
-  CellularRefPtr cellular_;
-  MockCellularService *service_;  // owned by cellular_
   scoped_ptr<mm1::MockModemModem3gppProxy> modem_3gpp_proxy_;
   scoped_ptr<mm1::MockModemModemCdmaProxy> modem_cdma_proxy_;
   scoped_ptr<mm1::MockModemProxy> modem_proxy_;
@@ -220,6 +219,8 @@
   CellularCapabilityUniversal *capability_;  // Owned by |cellular_|.
   NiceMock<DeviceMockAdaptor> *device_adaptor_;  // Owned by |cellular_|.
   mobile_provider_db *provider_db_;
+  CellularRefPtr cellular_;
+  MockCellularService *service_;  // owned by cellular_
   DBusPropertyMapsCallback scan_callback_;  // saved for testing scan operations
   DBusPathCallback connect_callback_;  // saved for testing connect operations
 };
diff --git a/cellular_service_unittest.cc b/cellular_service_unittest.cc
index 3834ff3..2393f57 100644
--- a/cellular_service_unittest.cc
+++ b/cellular_service_unittest.cc
@@ -8,11 +8,12 @@
 #include <gtest/gtest.h>
 
 #include "shill/cellular_capability.h"
-#include "shill/cellular_capability_gsm.h"
-#include "shill/nice_mock_control.h"
+#include "shill/cellular_capability_cdma.h"
 #include "shill/mock_adaptors.h"
 #include "shill/mock_metrics.h"
 #include "shill/mock_profile.h"
+#include "shill/nice_mock_control.h"
+#include "shill/proxy_factory.h"
 
 using std::string;
 using testing::_;
@@ -31,11 +32,12 @@
                              "usb0",
                              kAddress,
                              3,
-                             Cellular::kTypeGSM,
+                             Cellular::kTypeCDMA,
                              "",
                              "",
                              "",
-                             NULL)),
+                             NULL,
+                             ProxyFactory::GetInstance())),
         service_(new CellularService(&control_, NULL, &metrics_, NULL,
                                      device_)),
         adaptor_(NULL) {}
@@ -49,8 +51,8 @@
         dynamic_cast<NiceMock<ServiceMockAdaptor> *>(service_->adaptor());
   }
 
-  CellularCapabilityGSM *GetCapabilityGSM() {
-    return dynamic_cast<CellularCapabilityGSM *>(device_->capability_.get());
+  CellularCapabilityCDMA *GetCapabilityCDMA() {
+    return dynamic_cast<CellularCapabilityCDMA *>(device_->capability_.get());
   }
 
  protected:
@@ -89,7 +91,7 @@
 
 TEST_F(CellularServiceTest, FriendlyName) {
   static const char kCarrier[] = "Cellular Carrier";
-  GetCapabilityGSM()->carrier_ = kCarrier;
+  GetCapabilityCDMA()->carrier_ = kCarrier;
   service_ = new CellularService(&control_, NULL, &metrics_, NULL, device_);
   EXPECT_EQ(kCarrier, service_->friendly_name());
 }
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index 37b8e0f..ce74191 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -68,11 +68,12 @@
                              "usb0",
                              "00:01:02:03:04:05",
                              3,
-                             Cellular::kTypeGSM,
+                             Cellular::kTypeCDMA,
                              "",
                              "",
                              "",
-                             NULL)) {}
+                             NULL,
+                             ProxyFactory::GetInstance())) {}
   virtual ~CellularPropertyTest() {}
 
  protected:
@@ -119,6 +120,14 @@
         device_info_(&control_interface_, &dispatcher_, &metrics_, &manager_),
         dhcp_config_(new MockDHCPConfig(&control_interface_,
                                         kTestDeviceName)),
+        create_gsm_card_proxy_from_factory_(false),
+        proxy_(new MockModemProxy()),
+        simple_proxy_(new MockModemSimpleProxy()),
+        cdma_proxy_(new MockModemCDMAProxy()),
+        gsm_card_proxy_(new MockModemGSMCardProxy()),
+        gsm_network_proxy_(new MockModemGSMNetworkProxy()),
+        proxy_factory_(this),
+        provider_db_(NULL),
         device_(new Cellular(&control_interface_,
                              &dispatcher_,
                              &metrics_,
@@ -130,16 +139,8 @@
                              kDBusOwner,
                              kDBusService,
                              kDBusPath,
-                             NULL)),
-        proxy_(new MockModemProxy()),
-        simple_proxy_(new MockModemSimpleProxy()),
-        cdma_proxy_(new MockModemCDMAProxy()),
-        gsm_card_proxy_(new MockModemGSMCardProxy()),
-        gsm_network_proxy_(new MockModemGSMNetworkProxy()),
-        proxy_factory_(this),
-        provider_db_(NULL) {
-    device_->capability_->proxy_factory_ = &proxy_factory_;
-  }
+                             NULL,
+                             &proxy_factory_)) {}
 
   virtual ~CellularTest() {
     mobile_provider_close_db(provider_db_);
@@ -325,7 +326,12 @@
     virtual ModemGSMCardProxyInterface *CreateModemGSMCardProxy(
         const string &/*path*/,
         const string &/*service*/) {
-      return test_->gsm_card_proxy_.release();
+      // TODO(benchan): This code conditionally returns a NULL pointer to avoid
+      // CellularCapabilityGSM::InitProperties (and thus
+      // CellularCapabilityGSM::GetIMSI) from being called during the
+      // construction. Remove this workaround after refactoring the tests.
+      return test_->create_gsm_card_proxy_from_factory_ ?
+          test_->gsm_card_proxy_.release() : NULL;
     }
 
     virtual ModemGSMNetworkProxyInterface *CreateModemGSMNetworkProxy(
@@ -340,8 +346,12 @@
   void StartRTNLHandler();
   void StopRTNLHandler();
 
+  void AllowCreateGSMCardProxyFromFactory() {
+    create_gsm_card_proxy_from_factory_ = true;
+  }
+
   void SetCellularType(Cellular::Type type) {
-    device_->InitCapability(type, &proxy_factory_);
+    device_->InitCapability(type);
   }
 
   CellularCapabilityClassic *GetCapabilityClassic() {
@@ -368,7 +378,7 @@
   MockDHCPProvider dhcp_provider_;
   scoped_refptr<MockDHCPConfig> dhcp_config_;
 
-  CellularRefPtr device_;
+  bool create_gsm_card_proxy_from_factory_;
   scoped_ptr<MockModemProxy> proxy_;
   scoped_ptr<MockModemSimpleProxy> simple_proxy_;
   scoped_ptr<MockModemCDMAProxy> cdma_proxy_;
@@ -376,6 +386,7 @@
   scoped_ptr<MockModemGSMNetworkProxy> gsm_network_proxy_;
   TestProxyFactory proxy_factory_;
   mobile_provider_db *provider_db_;
+  CellularRefPtr device_;
 };
 
 const char CellularTest::kTestDeviceName[] = "usb0";
@@ -456,6 +467,8 @@
                              &CellularTest::InvokeGetSignalQuality));
   EXPECT_CALL(*this, TestCallback(IsSuccess()));
   EXPECT_CALL(manager_, RegisterService(_));
+  AllowCreateGSMCardProxyFromFactory();
+
   Error error;
   device_->Start(&error, Bind(&CellularTest::TestCallback, Unretained(this)));
   EXPECT_TRUE(error.IsSuccess());
diff --git a/mock_cellular.cc b/mock_cellular.cc
index 6b376b9..c631a8c 100644
--- a/mock_cellular.cc
+++ b/mock_cellular.cc
@@ -20,10 +20,11 @@
                            const std::string &owner,
                            const std::string &service,
                            const std::string &path,
-                           mobile_provider_db *provider_db)
+                           mobile_provider_db *provider_db,
+                           ProxyFactory *proxy_factory)
     : Cellular(control_interface, dispatcher, metrics, manager, link_name,
                address, interface_index, type, owner, service, path,
-               provider_db) {}
+               provider_db, proxy_factory) {}
 
 MockCellular::~MockCellular() {}
 
diff --git a/mock_cellular.h b/mock_cellular.h
index 882c5ef..8b5be05 100644
--- a/mock_cellular.h
+++ b/mock_cellular.h
@@ -27,10 +27,10 @@
                const std::string &owner,
                const std::string &service,
                const std::string &path,
-               mobile_provider_db *provider_db);
+               mobile_provider_db *provider_db,
+               ProxyFactory *proxy_factory);
   virtual ~MockCellular();
 
-  MOCK_METHOD2(InitCapability, void(Type, ProxyFactory *));
   MOCK_METHOD3(OnDBusPropertiesChanged, void(const std::string &,
                                              const DBusPropertiesMap &,
                                              const std::vector<std::string> &));
diff --git a/modem.cc b/modem.cc
index 62ab19f..1450971 100644
--- a/modem.cc
+++ b/modem.cc
@@ -92,7 +92,8 @@
                       owner_,
                       service_,
                       path_,
-                      provider_db_);
+                      provider_db_,
+                      ProxyFactory::GetInstance());
 }
 
 void Modem::CreateDeviceFromModemProperties(
diff --git a/modem_unittest.cc b/modem_unittest.cc
index d214c81..e010bcd 100644
--- a/modem_unittest.cc
+++ b/modem_unittest.cc
@@ -98,11 +98,6 @@
     ModemTest *test_;
   };
 
-  CellularCapabilityGSM *GetCapabilityGSM() {
-    return dynamic_cast<CellularCapabilityGSM *>(
-        modem_->device_->capability_.get());
-  }
-
   MockGLib glib_;
   MockControl control_interface_;
   EventDispatcher dispatcher_;
@@ -170,11 +165,12 @@
       kLinkName,
       kAddressAsString,
       kTestInterfaceIndex,
-      Cellular::kTypeGSM,
+      Cellular::kTypeCDMA,
       kOwner,
       kService,
       kPath,
-      static_cast<mobile_provider_db *>(NULL));
+      static_cast<mobile_provider_db *>(NULL),
+      ProxyFactory::GetInstance());
 
   EXPECT_CALL(*modem_,
               ConstructCellular(StrEq(kLinkName),