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_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();