shill: Enable auto-connect for WiFi services

This performs a few of the last tidbits to get auto-connect
working for WiFi networks.  The tweaks include:

  * Adding calls to SortServices() in Push/PopProfile
  * On successful connection, move service to the profile on
    the top of the stack if this service was previously in the
    ephemeral profile.
  * Add a method to Services to return whether they are eligible
    for auto-connect.  Implement this for the WiFi services by
    using a new method to test if the WiFi device is busy.

BUG=chromium-os:24261,chromium-os:17255
TEST=Unit Tests (for regression)
Manual: Connect to WPA-PSK network successfully; restart shill and
observe an auto-connect after scan.

Change-Id: Ia4e1fd94795a4ce64d66ec6db940ee16ff694431
Reviewed-on: https://gerrit.chromium.org/gerrit/12963
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Commit-Ready: Paul Stewart <pstew@chromium.org>
Tested-by: Paul Stewart <pstew@chromium.org>
diff --git a/manager.cc b/manager.cc
index fe5c36b..e26dffe 100644
--- a/manager.cc
+++ b/manager.cc
@@ -239,6 +239,8 @@
        it != devices_.end(); ++it) {
     profile->ConfigureDevice(*it);
   }
+
+  SortServices();
 }
 
 void Manager::PopProfileInternal() {
@@ -260,6 +262,7 @@
       }
     }
   }
+  SortServices();
 }
 
 void Manager::PopProfile(const string &name, Error *error) {
@@ -299,6 +302,12 @@
 bool Manager::MoveServiceToProfile(const ServiceRefPtr &to_move,
                                    const ProfileRefPtr &destination) {
   const ProfileRefPtr from = to_move->profile();
+  VLOG(2) << "Moving service "
+          << to_move->UniqueName()
+          << " to profile "
+          << destination->GetFriendlyName()
+          << " from "
+          << from->GetFriendlyName();
   return destination->AdoptService(to_move) &&
       from->AbandonService(to_move);
 }
@@ -408,8 +417,16 @@
             << " failure: "
             << Service::ConnectFailureToString(to_update->failure());
   LOG(INFO) << "IsConnected(): " << to_update->IsConnected();
-  if (to_update->IsConnected())
+  if (to_update->IsConnected()) {
     to_update->MakeFavorite();
+    if (to_update->profile().get() == ephemeral_profile_.get()) {
+      if (profiles_.empty()) {
+        LOG(ERROR) << "Cannot assign profile to service: no profiles exist!";
+      } else {
+        MoveServiceToProfile(to_update, profiles_.back());
+      }
+    }
+  }
   SortServices();
 }
 
@@ -484,6 +501,16 @@
       services_[0]->connection()->SetIsDefault(true);
     }
   }
+
+  // Perform auto-connect.
+  for (it = services_.begin(); it != services_.end(); ++it) {
+    if ((*it)->auto_connect() && (*it)->IsAutoConnectable()) {
+      Error error;
+      (*it)->Connect(&error);
+      // We intentionally ignore the error returned by Connect() here since it
+      // should not prevent us from trying to connect a different service.
+    }
+  }
 }
 
 string Manager::CalculateState(Error */*error*/) {