shill: Add device metrics registration for devices without link message.

Cellular devices may be created and registered without a preceding RTNL
link message.

BUG=chromium-os:38187
TEST=Restart modemmanager and make sure shill doesn't crash

Change-Id: I13697f53a007a5c4ff67106f980380db338fba64
Reviewed-on: https://gerrit.chromium.org/gerrit/41918
Reviewed-by: Ben Chan <benchan@chromium.org>
Commit-Queue: Thieu Le <thieule@chromium.org>
Tested-by: Thieu Le <thieule@chromium.org>
diff --git a/device_info.cc b/device_info.cc
index 75ab479..5cee01f 100644
--- a/device_info.cc
+++ b/device_info.cc
@@ -146,10 +146,15 @@
   delayed_devices_.erase(device->interface_index());
   CHECK(!GetDevice(device->interface_index()).get());
   infos_[device->interface_index()].device = device;
+  if (metrics_->IsDeviceRegistered(device->interface_index(),
+                                   device->technology())) {
+    metrics_->NotifyDeviceInitialized(device->interface_index());
+  } else {
+    metrics_->RegisterDevice(device->interface_index(), device->technology());
+  }
   if (Technology::IsPrimaryConnectivityTechnology(device->technology())) {
     manager_->RegisterDevice(device);
   }
-  metrics_->NotifyDeviceInitialized(device->interface_index());
 }
 
 void DeviceInfo::DeregisterDevice(const DeviceRefPtr &device) {
diff --git a/metrics.cc b/metrics.cc
index bbbd150..0025305 100644
--- a/metrics.cc
+++ b/metrics.cc
@@ -581,8 +581,10 @@
 
 void Metrics::RegisterDevice(int interface_index,
                              Technology::Identifier technology) {
+  SLOG(Metrics, 2) << __func__ << ": " << interface_index;
   shared_ptr<DeviceMetrics> device_metrics(new DeviceMetrics);
   devices_metrics_[interface_index] = device_metrics;
+  device_metrics->technology = technology;
   string histogram = GetFullMetricName(kMetricTimeToInitializeMilliseconds,
                                        technology);
   device_metrics->initialization_timer.reset(
@@ -610,7 +612,19 @@
           kMetricTimeToDisableMillisecondsNumBuckets));
 }
 
+bool Metrics::IsDeviceRegistered(int interface_index,
+                                 Technology::Identifier technology) {
+  SLOG(Metrics, 2) << __func__ << ": interface index: " << interface_index
+                               << ", technology: " << technology;
+  DeviceMetrics *device_metrics = GetDeviceMetrics(interface_index);
+  if (device_metrics == NULL)
+    return false;
+  // Make sure the device technologies match.
+  return (technology == device_metrics->technology);
+}
+
 void Metrics::DeregisterDevice(int interface_index) {
+  SLOG(Metrics, 2) << __func__ << ": interface index: " << interface_index;
   devices_metrics_.erase(interface_index);
 }
 
@@ -705,11 +719,12 @@
                           kMetricNetworkServiceErrorsMax);
 }
 
-Metrics::DeviceMetrics *Metrics::GetDeviceMetrics(int interface_index) {
-  DeviceMetricsLookupMap::iterator it = devices_metrics_.find(interface_index);
+Metrics::DeviceMetrics *Metrics::GetDeviceMetrics(int interface_index) const {
+  DeviceMetricsLookupMap::const_iterator it =
+      devices_metrics_.find(interface_index);
   if (it == devices_metrics_.end()) {
-    SLOG(Metrics, 1) << "device " << interface_index << " not found";
-    DCHECK(false);
+    SLOG(Metrics, 2) << __func__ << ": device " << interface_index
+                     << " not found";
     return NULL;
   }
   return it->second.get();
diff --git a/metrics.h b/metrics.h
index baa7613..9775692 100644
--- a/metrics.h
+++ b/metrics.h
@@ -331,6 +331,10 @@
   void RegisterDevice(int interface_index,
                       Technology::Identifier technology);
 
+  // Checks to see if the device has already been registered.
+  bool IsDeviceRegistered(int interface_index,
+                          Technology::Identifier technology);
+
   // Deregisters the device from this class.  All state transition timers
   // will be removed.
   void DeregisterDevice(int interface_index);
@@ -390,6 +394,7 @@
 
   struct DeviceMetrics {
     DeviceMetrics() {}
+    Technology::Identifier technology;
     scoped_ptr<chromeos_metrics::TimerReporter> initialization_timer;
     scoped_ptr<chromeos_metrics::TimerReporter> enable_timer;
     scoped_ptr<chromeos_metrics::TimerReporter> disable_timer;
@@ -417,7 +422,7 @@
                                            Service::ConnectState new_state);
   void SendServiceFailure(const Service *service);
 
-  DeviceMetrics *GetDeviceMetrics(int interface_index);
+  DeviceMetrics *GetDeviceMetrics (int interface_index) const;
 
   // For unit test purposes.
   void set_library(MetricsLibraryInterface *library);