shill: Disconnect before activation correctly

Allow cellular capabilities to correctly disconnect before activation by
only responding to the final disconnect notification.  Previously, shill
attempted to activate the modem upon receiving the first notification
after a disconnect operation, which is usually just a notification that
a disconnect is in progress.  Seeing that the modem hadn't actually
disconnected, shill would report the activation as failed.

The meat of this change is that CellularCapabilityCDMA stores away the
activation callback when it finds it is connected during an activation
attempt.  When the cellular device cleans up its disconnect process, it
calls down to the capability, giving us the opportunity to respond by
triggering our activation.

TEST=Unit tests, activations making use of this logic proceed correctly.
BUG=chromium-os:36301

Change-Id: I0169328403a805a06309a41b31e00b66657b9f5b
Reviewed-on: https://gerrit.chromium.org/gerrit/39028
Tested-by: Christopher Wiley <wiley@chromium.org>
Reviewed-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: Thieu Le <thieule@chromium.org>
Commit-Ready: Christopher Wiley <wiley@chromium.org>
diff --git a/cellular.cc b/cellular.cc
index 5290236..55dd803 100644
--- a/cellular.cc
+++ b/cellular.cc
@@ -468,8 +468,7 @@
     service_->SetFailure(Service::kFailureUnknown);
 }
 
-void Cellular::DisconnectWithCallback(const ResultCallback &callback,
-                                      Error *error) {
+void Cellular::Disconnect(Error *error) {
   SLOG(Cellular, 2) << __func__;
   if (state_ != kStateConnected && state_ != kStateLinked) {
     Error::PopulateAndLog(
@@ -477,17 +476,11 @@
     return;
   }
   ResultCallback cb = Bind(&Cellular::OnDisconnectReply,
-                           weak_ptr_factory_.GetWeakPtr(),
-                           callback);
+                           weak_ptr_factory_.GetWeakPtr());
   capability_->Disconnect(error, cb);
 }
 
-void Cellular::Disconnect(Error *error) {
-  DisconnectWithCallback(ResultCallback(), error);
-}
-
-void Cellular::OnDisconnectReply(const ResultCallback &callback,
-                                 const Error &error) {
+void Cellular::OnDisconnectReply(const Error &error) {
   SLOG(Cellular, 2) << __func__ << "(" << error << ")";
   if (error.IsSuccess())
     OnDisconnected();
@@ -495,9 +488,6 @@
     OnDisconnectFailed();
   manager()->TerminationActionComplete(FriendlyName());
   manager()->RemoveTerminationAction(FriendlyName());
-  if (!callback.is_null()) {
-    callback.Run(error);
-  }
 }
 
 void Cellular::OnDisconnected() {
@@ -664,13 +654,15 @@
 }
 
 bool Cellular::DisconnectCleanup() {
+  bool succeeded = false;
   if (state_ == kStateConnected || state_ == kStateLinked) {
     SetState(kStateRegistered);
     SetServiceFailureSilent(Service::kFailureUnknown);
     DestroyIPConfig();
-    return true;
+    succeeded = true;
   }
-  return false;
+  capability_->DisconnectCleanup();
+  return succeeded;
 }
 
 }  // namespace shill