shill: add disconnect reason to log messages

Allow logging of function/reason for triggering disconnect.

BUG=chromium:227295
TEST=unit tests

Change-Id: I92ea3cca664c060bc02bbb8d50d303ce11d1a7de
Reviewed-on: https://chromium-review.googlesource.com/207020
Tested-by: Samuel Tan <samueltan@chromium.org>
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Commit-Queue: Samuel Tan <samueltan@chromium.org>
diff --git a/active_passive_out_of_credits_detector.cc b/active_passive_out_of_credits_detector.cc
index 313ab95..e9d9d59 100644
--- a/active_passive_out_of_credits_detector.cc
+++ b/active_passive_out_of_credits_detector.cc
@@ -161,7 +161,7 @@
       ReportOutOfCredits(true);
       SLOG(Cellular, 2) << "Disconnecting due to out-of-credit scenario.";
       Error error;
-      service()->Disconnect(&error);
+      service()->Disconnect(&error, "out-of-credits");
     }
   }
 }
diff --git a/active_passive_out_of_credits_detector_unittest.cc b/active_passive_out_of_credits_detector_unittest.cc
index 3660f86..08cb4df 100644
--- a/active_passive_out_of_credits_detector_unittest.cc
+++ b/active_passive_out_of_credits_detector_unittest.cc
@@ -300,7 +300,7 @@
 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
     OnConnectionHealthCheckerResult) {
   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
-  EXPECT_CALL(*service_, Disconnect(_)).Times(0);
+  EXPECT_CALL(*service_, Disconnect(_, _)).Times(0);
   out_of_credits_detector_->OnConnectionHealthCheckerResult(
       ConnectionHealthChecker::kResultUnknown);
   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
@@ -309,7 +309,9 @@
   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
   Mock::VerifyAndClearExpectations(service_);
 
-  EXPECT_CALL(*service_, Disconnect(_)).Times(1);
+  EXPECT_CALL(*service_, Disconnect(_,
+      ::testing::StrEq("out-of-credits"))).
+          Times(1);
   out_of_credits_detector_->OnConnectionHealthCheckerResult(
       ConnectionHealthChecker::kResultCongestedTxQueue);
   EXPECT_TRUE(out_of_credits_detector_->out_of_credits());
diff --git a/cellular.cc b/cellular.cc
index c5f38ff..89d3f7b 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -760,11 +760,11 @@
   SetState(kStateConnected);
   if (!service_) {
     LOG(INFO) << "Disconnecting due to no cellular service.";
-    Disconnect(NULL);
+    Disconnect(NULL, "no celluar service");
   } else if (!capability_->AllowRoaming() &&
       service_->roaming_state() == kRoamingStateRoaming) {
     LOG(INFO) << "Disconnecting due to roaming.";
-    Disconnect(NULL);
+    Disconnect(NULL, "roaming");
   } else {
     EstablishLink();
   }
@@ -775,8 +775,8 @@
     service_->SetFailure(Service::kFailureUnknown);
 }
 
-void Cellular::Disconnect(Error *error) {
-  SLOG(Cellular, 2) << __func__;
+void Cellular::Disconnect(Error *error, const char *reason) {
+  SLOG(Cellular, 2) << __func__ << ": " << reason;
   if (state_ != kStateConnected && state_ != kStateLinked) {
     Error::PopulateAndLog(
         error, Error::kNotConnected, "Not connected; request ignored.");
@@ -980,7 +980,7 @@
   if (!capability_->AllowRoaming() &&
       capability_->GetRoamingStateString() == kRoamingStateRoaming) {
     Error error;
-    Disconnect(&error);
+    Disconnect(&error, __func__);
   }
   adaptor()->EmitBoolChanged(kCellularAllowRoamingProperty, value);
   return true;
@@ -1175,7 +1175,7 @@
     SetServiceFailure(Service::kFailureUnknown);
   }
   Error error;
-  Disconnect(&error);
+  Disconnect(&error, __func__);
 }
 
 void Cellular::OnPPPDied(pid_t pid, int exit) {
diff --git a/cellular.h b/cellular.h
index 08a6399..fd81ae2 100644
--- a/cellular.h
+++ b/cellular.h
@@ -129,7 +129,7 @@
 
   // Asynchronously disconnects the modem from the network and populates
   // |error| on failure, leaves it unchanged otherwise.
-  virtual void Disconnect(Error *error);
+  virtual void Disconnect(Error *error, const char *reason);
 
   // Asynchronously activates the modem. Returns an error on failure.
   void Activate(const std::string &carrier, Error *error,
diff --git a/cellular_capability_cdma.cc b/cellular_capability_cdma.cc
index 5fc1c5e..5c316fa 100644
--- a/cellular_capability_cdma.cc
+++ b/cellular_capability_cdma.cc
@@ -156,7 +156,7 @@
              cellular()->state() == Cellular::kStateLinked) {
     pending_activation_callback_ = callback;
     pending_activation_carrier_ = carrier;
-    cellular()->Disconnect(error);
+    cellular()->Disconnect(error, __func__);
   } else {
     Error::PopulateAndLog(error, Error::kInvalidArguments,
                           "Unable to activate in " +
diff --git a/cellular_capability_cdma_unittest.cc b/cellular_capability_cdma_unittest.cc
index f99a1ee..802edb4 100644
--- a/cellular_capability_cdma_unittest.cc
+++ b/cellular_capability_cdma_unittest.cc
@@ -27,6 +27,7 @@
 using testing::InSequence;
 using testing::Invoke;
 using testing::Return;
+using testing::StrEq;
 
 namespace shill {
 
@@ -166,7 +167,7 @@
   {
     InSequence dummy;
 
-    EXPECT_CALL(*cellular_, Disconnect(_));
+    EXPECT_CALL(*cellular_, Disconnect(_, StrEq("Activate")));
     EXPECT_CALL(*proxy_, Activate(kTestCarrier, _, _,
                                   CellularCapability::kTimeoutActivate))
         .WillOnce(Invoke(this,
@@ -201,7 +202,7 @@
   {
     InSequence dummy;
 
-    EXPECT_CALL(*cellular_, Disconnect(_));
+    EXPECT_CALL(*cellular_, Disconnect(_, StrEq("Activate")));
     EXPECT_CALL(*proxy_, Activate(kTestCarrier, _, _,
                                   CellularCapability::kTimeoutActivate))
         .Times(0);
diff --git a/cellular_service.cc b/cellular_service.cc
index 99ddddb..cc969bb 100644
--- a/cellular_service.cc
+++ b/cellular_service.cc
@@ -314,9 +314,9 @@
     out_of_credits_detector_->ResetDetector();
 }
 
-void CellularService::Disconnect(Error *error) {
-  Service::Disconnect(error);
-  cellular_->Disconnect(error);
+void CellularService::Disconnect(Error *error, const char *reason) {
+  Service::Disconnect(error, reason);
+  cellular_->Disconnect(error, reason);
 }
 
 void CellularService::ActivateCellularModem(const string &carrier,
diff --git a/cellular_service.h b/cellular_service.h
index 209eb15..7bb1f01 100644
--- a/cellular_service.h
+++ b/cellular_service.h
@@ -34,7 +34,7 @@
   // Inherited from Service.
   virtual void AutoConnect();
   virtual void Connect(Error *error, const char *reason);
-  virtual void Disconnect(Error *error);
+  virtual void Disconnect(Error *error, const char *reason);
   virtual void ActivateCellularModem(const std::string &carrier,
                                      Error *error,
                                      const ResultCallback &callback);
diff --git a/cellular_service_unittest.cc b/cellular_service_unittest.cc
index b8908a5..b5dcae6 100644
--- a/cellular_service_unittest.cc
+++ b/cellular_service_unittest.cc
@@ -402,7 +402,7 @@
   EXPECT_TRUE(service_->IsAutoConnectable(&reason));
 
   // A non-user initiated Disconnect doesn't change anything.
-  service_->Disconnect(&error);
+  service_->Disconnect(&error, "in test");
   EXPECT_TRUE(service_->IsAutoConnectable(&reason));
 
   // A resume also re-enables auto-connect.
diff --git a/cellular_unittest.cc b/cellular_unittest.cc
index 270a275..8682e9f 100644
--- a/cellular_unittest.cc
+++ b/cellular_unittest.cc
@@ -1162,7 +1162,7 @@
 TEST_F(CellularTest, Disconnect) {
   Error error;
   device_->state_ = Cellular::kStateRegistered;
-  device_->Disconnect(&error);
+  device_->Disconnect(&error, "in test");
   EXPECT_EQ(Error::kNotConnected, error.type());
   error.Reset();
 
@@ -1171,7 +1171,7 @@
               Disconnect(_, _, CellularCapability::kTimeoutDisconnect))
       .WillOnce(Invoke(this, &CellularTest::InvokeDisconnect));
   GetCapabilityClassic()->proxy_.reset(proxy_.release());
-  device_->Disconnect(&error);
+  device_->Disconnect(&error, "in test");
   EXPECT_TRUE(error.IsSuccess());
   EXPECT_EQ(Cellular::kStateRegistered, device_->state_);
 }
@@ -1187,12 +1187,12 @@
        .WillRepeatedly(Invoke(this, &CellularTest::InvokeDisconnectFail));
   GetCapabilityClassic()->proxy_.reset(proxy_.release());
   device_->modem_state_ = Cellular::kModemStateDisconnecting;
-  device_->Disconnect(&error);
+  device_->Disconnect(&error, "in test");
   EXPECT_TRUE(error.IsFailure());
   EXPECT_EQ(Cellular::kStateConnected, device_->state_);
 
   device_->modem_state_ = Cellular::kModemStateConnected;
-  device_->Disconnect(&error);
+  device_->Disconnect(&error, "in test");
   EXPECT_TRUE(error.IsFailure());
   EXPECT_EQ(Cellular::kStateRegistered, device_->state_);
 }
@@ -1704,7 +1704,7 @@
   StartPPP(kPID);
   FakeUpConnectedPPP();
   ExpectPPPStopped();
-  device_->Disconnect(&error);
+  device_->Disconnect(&error, "in test");
   VerifyPPPStopped();
 }
 
diff --git a/device.cc b/device.cc
index 2c6d4fb..062cd4b 100644
--- a/device.cc
+++ b/device.cc
@@ -618,7 +618,9 @@
 void Device::OnIPConfigFailure() {
   if (selected_service_) {
     Error error;
-    selected_service_->DisconnectWithFailure(Service::kFailureDHCP, &error);
+    selected_service_->DisconnectWithFailure(Service::kFailureDHCP,
+                                             &error,
+                                             __func__);
   }
 }
 
diff --git a/device_unittest.cc b/device_unittest.cc
index d6c616c..5e9bdb3 100644
--- a/device_unittest.cc
+++ b/device_unittest.cc
@@ -393,7 +393,9 @@
                                   metrics(),
                                   manager()));
   SelectService(service);
-  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureDHCP, _));
+  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureDHCP,
+                                              _,
+                                              StrEq("OnIPConfigFailure")));
   EXPECT_CALL(*service, SetConnection(IsNullRefPtr()));
   EXPECT_CALL(*ipconfig, ResetProperties());
   OnIPConfigFailed(ipconfig.get());
@@ -412,7 +414,7 @@
   service->static_ip_parameters_.args_.SetInt(kPrefixlenProperty, 16);
   // Even though we won't call DisconnectWithFailure, we should still have
   // the service learn from the failed DHCP attempt.
-  EXPECT_CALL(*service, DisconnectWithFailure(_, _)).Times(0);
+  EXPECT_CALL(*service, DisconnectWithFailure(_, _, _)).Times(0);
   EXPECT_CALL(*service, SetConnection(_)).Times(0);
   // The IPConfig should retain the previous values.
   EXPECT_CALL(*ipconfig, ResetProperties()).Times(0);
diff --git a/ethernet_service.cc b/ethernet_service.cc
index 4230690..242710f 100644
--- a/ethernet_service.cc
+++ b/ethernet_service.cc
@@ -51,7 +51,8 @@
   ethernet_->ConnectTo(this);
 }
 
-void EthernetService::Disconnect(Error */*error*/) {
+void EthernetService::Disconnect(Error *error, const char *reason) {
+  Service::Disconnect(error, reason);
   ethernet_->DisconnectFrom(this);
 }
 
diff --git a/ethernet_service.h b/ethernet_service.h
index cda730d..813b9c4 100644
--- a/ethernet_service.h
+++ b/ethernet_service.h
@@ -32,7 +32,7 @@
 
   // Inherited from Service.
   virtual void Connect(Error *error, const char *reason);
-  virtual void Disconnect(Error *error);
+  virtual void Disconnect(Error *error, const char *reason);
 
   // ethernet_<MAC>
   virtual std::string GetStorageIdentifier() const;
diff --git a/ethernet_service_unittest.cc b/ethernet_service_unittest.cc
index 16027d0..df72e87 100644
--- a/ethernet_service_unittest.cc
+++ b/ethernet_service_unittest.cc
@@ -86,7 +86,7 @@
   service_->AutoConnect();
   EXPECT_CALL(*ethernet_, DisconnectFrom(service_.get()));
   Error error;
-  service_->Disconnect(&error);
+  service_->Disconnect(&error, "in test");
 }
 
 TEST_F(EthernetServiceTest, PropertyChanges) {
diff --git a/manager.cc b/manager.cc
index 9b96171..3961349 100644
--- a/manager.cc
+++ b/manager.cc
@@ -245,7 +245,7 @@
 
   Error e;
   for (const auto &service : services_) {
-    service->Disconnect(&e);
+    service->Disconnect(&e, __func__);
   }
 
   adaptor_->UpdateRunning();
diff --git a/manager_unittest.cc b/manager_unittest.cc
index aec05bb..35dfeea 100644
--- a/manager_unittest.cc
+++ b/manager_unittest.cc
@@ -2841,7 +2841,7 @@
       .WillOnce(Return(true));
   EXPECT_CALL(*profile.get(), UpdateWiFiProvider(_)).WillOnce(Return(true));
   EXPECT_CALL(*profile.get(), Save()).WillOnce(Return(true));
-  EXPECT_CALL(*service.get(), Disconnect(_)).Times(1);
+  EXPECT_CALL(*service.get(), Disconnect(_, StrEq("Stop"))).Times(1);
   manager()->Stop();
   EXPECT_FALSE(manager()->power_manager());
 }
diff --git a/mock_cellular.h b/mock_cellular.h
index a29358f..e6430be 100644
--- a/mock_cellular.h
+++ b/mock_cellular.h
@@ -28,7 +28,7 @@
   virtual ~MockCellular();
 
   MOCK_METHOD1(Connect, void(Error *error));
-  MOCK_METHOD1(Disconnect, void(Error *error));
+  MOCK_METHOD2(Disconnect, void(Error *error, const char *reason));
   MOCK_METHOD3(OnDBusPropertiesChanged, void(
       const std::string &interface,
       const DBusPropertiesMap &changed_properties,
diff --git a/mock_cellular_service.h b/mock_cellular_service.h
index 3284d8a..67a7fb6 100644
--- a/mock_cellular_service.h
+++ b/mock_cellular_service.h
@@ -24,7 +24,7 @@
   MOCK_METHOD0(ClearLastGoodApn, void());
   MOCK_METHOD1(SetActivationState, void(const std::string &state));
   MOCK_METHOD2(Connect, void(Error *error, const char *reason));
-  MOCK_METHOD1(Disconnect, void(Error *error));
+  MOCK_METHOD2(Disconnect, void(Error *error, const char *reason));
   MOCK_METHOD1(SetState, void(ConnectState state));
   MOCK_METHOD1(SetFailure, void(ConnectFailure failure));
   MOCK_METHOD1(SetFailureSilent, void(ConnectFailure failure));
diff --git a/mock_ethernet_service.h b/mock_ethernet_service.h
index beb808b..0241fba 100644
--- a/mock_ethernet_service.h
+++ b/mock_ethernet_service.h
@@ -22,8 +22,8 @@
                                          size_t depth));
   MOCK_METHOD0(ClearEAPCertification, void());
   MOCK_METHOD2(Configure, void(const KeyValueStore &args, Error *error));
-  MOCK_METHOD2(DisconnectWithFailure,
-               void(ConnectFailure failure, Error *error));
+  MOCK_METHOD3(DisconnectWithFailure,
+               void(ConnectFailure failure, Error *error, const char *reason));
   MOCK_CONST_METHOD1(GetDeviceRpcId, std::string(Error *error));
   MOCK_CONST_METHOD0(GetStorageIdentifier, std::string());
   MOCK_CONST_METHOD0(Is8021xConnectable, bool());
diff --git a/mock_service.h b/mock_service.h
index 2185519..6669463 100644
--- a/mock_service.h
+++ b/mock_service.h
@@ -28,9 +28,10 @@
 
   MOCK_METHOD0(AutoConnect, void());
   MOCK_METHOD2(Connect, void(Error *error, const char *reason));
-  MOCK_METHOD1(Disconnect, void(Error *error));
-  MOCK_METHOD2(DisconnectWithFailure, void(Service::ConnectFailure failure,
-                                           Error *error));
+  MOCK_METHOD2(Disconnect, void(Error *error, const char *reason));
+  MOCK_METHOD3(DisconnectWithFailure, void(Service::ConnectFailure failure,
+                                           Error *error,
+                                           const char *reason));
   MOCK_METHOD1(UserInitiatedDisconnect, void(Error *error));
   MOCK_METHOD1(CalculateState, std::string(Error *error));
   MOCK_CONST_METHOD0(state, ConnectState());
diff --git a/mock_wifi_service.h b/mock_wifi_service.h
index 7cc6938..df4892a 100644
--- a/mock_wifi_service.h
+++ b/mock_wifi_service.h
@@ -44,8 +44,8 @@
                void(const WiFiEndpointConstRefPtr &endpoint));
   MOCK_METHOD1(NotifyEndpointUpdated,
                void(const WiFiEndpointConstRefPtr &endpoint));
-  MOCK_METHOD2(DisconnectWithFailure,
-               void(ConnectFailure failure, Error *error));
+  MOCK_METHOD3(DisconnectWithFailure,
+               void(ConnectFailure failure, Error *error, const char *reason));
   MOCK_CONST_METHOD0(IsConnected, bool());
   MOCK_CONST_METHOD0(IsConnecting, bool());
   MOCK_CONST_METHOD0(GetEndpointCount, int());
diff --git a/service.cc b/service.cc
index 09ac760..9d02583 100644
--- a/service.cc
+++ b/service.cc
@@ -278,17 +278,19 @@
     SetState(kStateIdle);
 }
 
-void Service::Disconnect(Error */*error*/) {
-  LOG(INFO) << "Disconnecting from service " << unique_name_;
+void Service::Disconnect(Error */*error*/, const char *reason) {
+  LOG(INFO) << "Disconnecting from service " << unique_name_ << ": " << reason;
 }
 
-void Service::DisconnectWithFailure(ConnectFailure failure, Error *error) {
-  Disconnect(error);
+void Service::DisconnectWithFailure(ConnectFailure failure,
+                                    Error *error,
+                                    const char *reason) {
+  Disconnect(error, reason);
   SetFailure(failure);
 }
 
 void Service::UserInitiatedDisconnect(Error *error) {
-  Disconnect(error);
+  Disconnect(error, "D-Bus RPC");
   explicitly_disconnected_ = true;
 }
 
@@ -502,7 +504,7 @@
   ClearEAPCertification();
 
   Error error;  // Ignored.
-  Disconnect(&error);
+  Disconnect(&error, __func__);
   return false;
 }
 
diff --git a/service.h b/service.h
index d6589c5..ce8b708 100644
--- a/service.h
+++ b/service.h
@@ -149,10 +149,12 @@
   virtual void Connect(Error *error, const char *reason);
   // Disconnect this service.  Override this method to add your service specific
   // disconnect logic, but call the super class's Disconnect() first.
-  virtual void Disconnect(Error *error);
+  virtual void Disconnect(Error *error, const char *reason);
   // Disconnects this service via Disconnect().  Marks the service as having
   // failed with |failure|.  Do not override this method.
-  virtual void DisconnectWithFailure(ConnectFailure failure, Error *error);
+  virtual void DisconnectWithFailure(ConnectFailure failure,
+                                     Error *error,
+                                     const char *reason);
   // Disconnects this service via Disconnect(). The service will not be eligible
   // for auto-connect until a subsequent call to Connect, or Load.  Do not
   // override this method.
diff --git a/service_unittest.cc b/service_unittest.cc
index 0e46711..155046b 100644
--- a/service_unittest.cc
+++ b/service_unittest.cc
@@ -866,7 +866,7 @@
   EXPECT_TRUE(service_->IsAutoConnectable(&reason));
 
   // A non-user initiated Disconnect doesn't change anything.
-  service_->Disconnect(&error);
+  service_->Disconnect(&error, "in test");
   EXPECT_TRUE(service_->IsAutoConnectable(&reason));
 
   // A resume also re-enables auto-connect.
diff --git a/vpn_service.cc b/vpn_service.cc
index f45d29a..4a6cb2b 100644
--- a/vpn_service.cc
+++ b/vpn_service.cc
@@ -67,9 +67,9 @@
   driver_->Connect(this, error);
 }
 
-void VPNService::Disconnect(Error *error) {
+void VPNService::Disconnect(Error *error, const char *reason) {
   LOG(INFO) << "Disconnect from service " << unique_name();
-  Service::Disconnect(error);
+  Service::Disconnect(error, reason);
   driver_->Disconnect();
 }
 
diff --git a/vpn_service.h b/vpn_service.h
index 50e0614..3ac9171 100644
--- a/vpn_service.h
+++ b/vpn_service.h
@@ -29,7 +29,7 @@
 
   // Inherited from Service.
   virtual void Connect(Error *error, const char *reason);
-  virtual void Disconnect(Error *error);
+  virtual void Disconnect(Error *error, const char *reason);
   virtual std::string GetStorageIdentifier() const;
   virtual bool Load(StoreInterface *storage);
   virtual bool Save(StoreInterface *storage);
diff --git a/vpn_service_unittest.cc b/vpn_service_unittest.cc
index ffe5818..be48042 100644
--- a/vpn_service_unittest.cc
+++ b/vpn_service_unittest.cc
@@ -136,7 +136,7 @@
 TEST_F(VPNServiceTest, Disconnect) {
   Error error;
   EXPECT_CALL(*driver_, Disconnect());
-  service_->Disconnect(&error);
+  service_->Disconnect(&error, "in test");
   EXPECT_TRUE(error.IsSuccess());
 }
 
diff --git a/wifi.cc b/wifi.cc
index 56ae94a..f9ef8de 100644
--- a/wifi.cc
+++ b/wifi.cc
@@ -1216,7 +1216,7 @@
     // Avoid a reporting failure twice by resetting EAP state handler early.
     eap_state_handler_->Reset();
     Error unused_error;
-    current_service_->DisconnectWithFailure(failure, &unused_error);
+    current_service_->DisconnectWithFailure(failure, &unused_error, __func__);
   }
 }
 
@@ -1704,7 +1704,8 @@
     // may not be correct.
     Error error;
     current_service_->DisconnectWithFailure(Service::kFailureBadPassphrase,
-                                            &error);
+                                            &error,
+                                            __func__);
     return;
   }
 
@@ -1797,7 +1798,7 @@
   SetScanState(kScanFoundNothing, scan_method_, __func__);
   WiFiServiceRefPtr pending_service = pending_service_;
   pending_service_->DisconnectWithFailure(
-      Service::kFailureOutOfRange, &unused_error);
+      Service::kFailureOutOfRange, &unused_error, __func__);
 
   // A hidden service may have no endpoints, since wpa_supplicant
   // failed to attain a CurrentBSS.  If so, the service has no
diff --git a/wifi_service.cc b/wifi_service.cc
index 418e1f6..b97b1d0 100644
--- a/wifi_service.cc
+++ b/wifi_service.cc
@@ -627,8 +627,8 @@
 }
 
 
-void WiFiService::Disconnect(Error *error) {
-  Service::Disconnect(error);
+void WiFiService::Disconnect(Error *error, const char *reason) {
+  Service::Disconnect(error, reason);
   if (!wifi_) {
     // If we are connecting to a hidden service, but have not yet found
     // any endpoints, we could end up with a disconnect request without
diff --git a/wifi_service.h b/wifi_service.h
index 6097c95..e9cf63c 100644
--- a/wifi_service.h
+++ b/wifi_service.h
@@ -52,7 +52,7 @@
 
   // Inherited from Service.
   virtual void Connect(Error *error, const char *reason);
-  virtual void Disconnect(Error *error);
+  virtual void Disconnect(Error *error, const char *reason);
   virtual bool Is8021x() const;
 
   virtual void AddEndpoint(const WiFiEndpointConstRefPtr &endpoint);
diff --git a/wifi_service_unittest.cc b/wifi_service_unittest.cc
index 58efa36..266304d 100644
--- a/wifi_service_unittest.cc
+++ b/wifi_service_unittest.cc
@@ -1088,14 +1088,14 @@
   WiFiServiceRefPtr service = MakeServiceWithWiFi(kSecurityWep);
   EXPECT_CALL(*wifi(), DisconnectFrom(service.get())).Times(1);
   Error error;
-  service->Disconnect(&error);
+  service->Disconnect(&error, "in test");
 }
 
 TEST_F(WiFiServiceTest, DisconnectWithoutWiFi) {
   WiFiServiceRefPtr service = MakeSimpleService(kSecurityWep);
   EXPECT_CALL(*wifi(), DisconnectFrom(_)).Times(0);
   Error error;
-  service->Disconnect(&error);
+  service->Disconnect(&error, "in test");
   EXPECT_EQ(Error::kOperationFailed, error.type());
 }
 
@@ -1108,7 +1108,7 @@
   EXPECT_CALL(log, Log(logging::LOG_ERROR, _,
                        HasSubstr("WiFi endpoints do not (yet) exist.")));
   Error error;
-  service->Disconnect(&error);
+  service->Disconnect(&error, "in test");
   EXPECT_EQ(Error::kOperationFailed, error.type());
 }
 
diff --git a/wifi_unittest.cc b/wifi_unittest.cc
index e1c7084..15746c1 100644
--- a/wifi_unittest.cc
+++ b/wifi_unittest.cc
@@ -1754,7 +1754,9 @@
   EXPECT_FALSE(pending_timeout.IsCancelled());
   EXPECT_EQ(service, GetPendingService());
   // Simulate a service with a wifi_ reference calling DisconnectFrom().
-  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureOutOfRange, _))
+  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureOutOfRange,
+                                              _,
+                                              StrEq("PendingTimeoutHandler")))
       .WillOnce(InvokeWithoutArgs(this, &WiFiObjectTest::ResetPendingService));
   EXPECT_CALL(*service, HasEndpoints()).Times(0);
   // DisconnectFrom() should not be called directly from WiFi.
@@ -1790,7 +1792,9 @@
   EXPECT_EQ(service, GetPendingService());
   // We expect the service to get a disconnect call, but in this scenario
   // the service does nothing.
-  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureOutOfRange, _));
+  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureOutOfRange,
+                                              _,
+                                              StrEq("PendingTimeoutHandler")));
   EXPECT_CALL(*service, HasEndpoints()).WillOnce(Return(false));
   // DisconnectFrom() should be called directly from WiFi.
   EXPECT_CALL(*service, SetState(Service::kStateIdle)).Times(AtLeast(1));
@@ -2647,7 +2651,9 @@
   // If there was an increased byte-count while we were timing out DHCP,
   // this should be considered a DHCP failure and not a credential failure.
   EXPECT_CALL(*service, ResetSuspectedCredentialFailures()).Times(0);
-  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureDHCP, _));
+  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureDHCP,
+                                              _,
+                                              StrEq("OnIPConfigFailure")));
   ReportIPConfigFailure();
   Mock::VerifyAndClearExpectations(service);
 
@@ -2655,7 +2661,9 @@
   // due to a passphrase issue.
   EXPECT_CALL(*service, AddSuspectedCredentialFailure())
       .WillOnce(Return(false));
-  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureDHCP, _));
+  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureDHCP,
+                                              _,
+                                              StrEq("OnIPConfigFailure")));
   ReportIPConfigFailure();
   Mock::VerifyAndClearExpectations(service);
 
@@ -2664,7 +2672,9 @@
   EXPECT_CALL(*service, AddSuspectedCredentialFailure())
       .WillOnce(Return(true));
   EXPECT_CALL(*service,
-              DisconnectWithFailure(Service::kFailureBadPassphrase, _));
+              DisconnectWithFailure(Service::kFailureBadPassphrase,
+                                    _,
+                                    StrEq("OnIPConfigFailure")));
   ReportIPConfigFailure();
 }
 
@@ -3069,7 +3079,9 @@
   EXPECT_CALL(*eap_state_handler_, ParseStatus(kEAPStatus, kEAPParameter, _))
       .WillOnce(DoAll(SetArgumentPointee<2>(Service::kFailureOutOfRange),
                 Return(false)));
-  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureOutOfRange, _));
+  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailureOutOfRange,
+                                              _,
+                                              StrEq("EAPEventTask")));
   ReportEAPEvent(kEAPStatus, kEAPParameter);
 
   MockEapCredentials *eap = new MockEapCredentials();
@@ -3082,7 +3094,9 @@
   // We need a real string object since it will be returned by reference below.
   const string kEmptyPin;
   EXPECT_CALL(*eap, pin()).WillOnce(ReturnRef(kEmptyPin));
-  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailurePinMissing, _));
+  EXPECT_CALL(*service, DisconnectWithFailure(Service::kFailurePinMissing,
+                                              _,
+                                              StrEq("EAPEventTask")));
   ReportEAPEvent(kEAPStatus, kEAPParameter);
 
   EXPECT_CALL(*eap_state_handler_, ParseStatus(kEAPStatus, kEAPParameter, _))
@@ -3091,7 +3105,7 @@
   // We need a real string object since it will be returned by reference below.
   const string kPin("000000");
   EXPECT_CALL(*eap, pin()).WillOnce(ReturnRef(kPin));
-  EXPECT_CALL(*service, DisconnectWithFailure(_, _)).Times(0);
+  EXPECT_CALL(*service, DisconnectWithFailure(_, _, _)).Times(0);
   EXPECT_CALL(*GetSupplicantInterfaceProxy(),
               NetworkReply(StrEq(kNetworkRpcId),
                            StrEq(WPASupplicant::kEAPRequestedParameterPIN),
diff --git a/wimax_service.cc b/wimax_service.cc
index 289deb6..e7f5689 100644
--- a/wimax_service.cc
+++ b/wimax_service.cc
@@ -158,14 +158,14 @@
   }
 }
 
-void WiMaxService::Disconnect(Error *error) {
+void WiMaxService::Disconnect(Error *error, const char *reason) {
   SLOG(WiMax, 2) << __func__;
   if (!device_) {
     Error::PopulateAndLog(
         error, Error::kNotConnected, "Not connected.");
     return;
   }
-  Service::Disconnect(error);
+  Service::Disconnect(error, reason);
   device_->DisconnectFrom(this, error);
   SetDevice(NULL);
 }
diff --git a/wimax_service.h b/wimax_service.h
index b18ff4a..2d8c725 100644
--- a/wimax_service.h
+++ b/wimax_service.h
@@ -69,7 +69,7 @@
 
   // Inherited from Service.
   virtual void Connect(Error *error, const char *reason);
-  virtual void Disconnect(Error *error);
+  virtual void Disconnect(Error *error, const char *reason);
   virtual std::string GetStorageIdentifier() const;
   virtual bool Is8021x() const;
   virtual bool IsVisible() const;
diff --git a/wimax_service_unittest.cc b/wimax_service_unittest.cc
index ec22cc4..6687e26 100644
--- a/wimax_service_unittest.cc
+++ b/wimax_service_unittest.cc
@@ -253,12 +253,12 @@
   EXPECT_CALL(*eap_, set_password(_)).Times(0);
   EXPECT_CALL(*device_, DisconnectFrom(_, _));
   error.Reset();
-  service_->Disconnect(&error);
+  service_->Disconnect(&error, "in test");
   EXPECT_TRUE(error.IsSuccess());
   EXPECT_TRUE(service_->connectable());
 
   // Disconnect while not connected.
-  service_->Disconnect(&error);
+  service_->Disconnect(&error, "in test");
   EXPECT_EQ(Error::kNotConnected, error.type());
 }