shill: wifi: Load hidden services from storage

When a device or profile comes into existence, the device
will search the profile for hidden services and instantiate
services if they do not exist.  These services will not
be visible in the RPC service list until they either appear
in scan or are actively being connected.

Side effects:
  * Manager now loads the devices with profile data.
  * Manager now respects the "powered" attribute loaded by
    devices from the profile to determine whether or not
    to call Start() on them.
  * Key files can be searched for groups with a certain
    key.  This will be useful when we start supporting GUIDs.
  * On service registration go backward (from top of stack
    downward) through the list of profiles searching for
    configuration instead of forwards.
  * Move the update of the "Services" property of the manager
    to a more centralized spot in SortServices.  This way,
    when the service order changes (or anything else that
    affects the service list) this RPC property will update.
  * Hidden services are not scanned for if they are in the
    ephemeral profile -- it means that whatever profile was
    supporting them does not exist anymore.
  * WiFi services have the unenviable task of also decoding
    storage identifiers in order to glean the address, mode
    and security parameters.

BUG=chromium-os:22073,chromium-os:22074
TEST=New unit tests, Manual on real hardware.
Note: I could not connect to a hidden network, but this
is because we're not setting the ApScan parameter on
wpa_supplicant so on connect it is just doing broadcast
scans.  However if I seed the profile with with a record
containing a hidden SSID, shill will force a scan for
the hidden network, which will allow it to connect.

Change-Id: I97a5b5f6db7c6e6d2aabf212c5c2984ce7f4daaa
Reviewed-on: https://gerrit.chromium.org/gerrit/11558
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 b61f7aa..43d0341 100644
--- a/manager.cc
+++ b/manager.cc
@@ -148,7 +148,7 @@
   device_info_.Stop();
 }
 
-void Manager::CreateProfile(const std::string &name, Error *error) {
+void Manager::CreateProfile(const string &name, Error *error) {
   Profile::Identifier ident;
   if (!Profile::ParseIdentifier(name, &ident)) {
     Error::PopulateAndLog(error, Error::kInvalidArguments,
@@ -216,13 +216,17 @@
   profiles_.push_back(profile);
 
   // Offer each registered Service the opportunity to join this new Profile.
-  vector<ServiceRefPtr>::iterator it;
-  for (it = services_.begin(); it != services_.end(); ++it) {
+  for (vector<ServiceRefPtr>::iterator it = services_.begin();
+       it != services_.end(); ++it) {
     profile->ConfigureService(*it);
   }
 
-  // TODO(pstew): Now shop the Profile contents around to Devices which
-  // can create non-visible services.
+  // Shop the Profile contents around to Devices which can create
+  // non-visible services.
+  for (vector<DeviceRefPtr>::iterator it = devices_.begin();
+       it != devices_.end(); ++it) {
+    profile->ConfigureDevice(*it);
+  }
 }
 
 void Manager::PopProfileInternal() {
@@ -240,12 +244,13 @@
       }
       if (p_it == profiles_.rend()) {
         ephemeral_profile_->AdoptService(*s_it);
+        (*s_it)->Unload();
       }
     }
   }
 }
 
-void Manager::PopProfile(const std::string &name, Error *error) {
+void Manager::PopProfile(const string &name, Error *error) {
   Profile::Identifier ident;
   if (profiles_.empty()) {
     Error::PopulateAndLog(error, Error::kNotFound, "Profile stack is empty");
@@ -294,16 +299,25 @@
   }
   devices_.push_back(to_manage);
 
-  // TODO(pstew): Should check configuration
-  if (running_)
-    to_manage->Start();
-
-  // NB: Should we keep a ptr to default profile and only persist that here?
+  // We are applying device properties from the DefaultProfile, and adding
+  // the union of hidden services in all loaded profiles to the device.
   for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
        it != profiles_.end();
        ++it) {
+    // Load device configuration, if any exists, as well as hidden services.
+    (*it)->ConfigureDevice(to_manage);
+
+    // Currently the only profile for which "Save" is implemented is the
+    // DefaultProfile.  It iterates over all Devices and stores their state.
+    // We perform the Save now in case the device we have just registered
+    // is new and needs to be added to the stored DefaultProfile.
     (*it)->Save();
   }
+
+  // In normal usage, running_ will always be true when we are here, however
+  // unit tests sometimes do things in otherwise invalid states.
+  if (running_ && to_manage->powered())
+    to_manage->Start();
 }
 
 void Manager::DeregisterDevice(const DeviceRefPtr &to_forget) {
@@ -323,8 +337,8 @@
   VLOG(2) << __func__ << to_manage->UniqueName();
 
   bool configured = false;
-  for (vector<ProfileRefPtr>::iterator it = profiles_.begin();
-       !configured && it != profiles_.end();
+  for (vector<ProfileRefPtr>::reverse_iterator it = profiles_.rbegin();
+       !configured && it != profiles_.rend();
        ++it) {
     configured = (*it)->ConfigureService(to_manage);
   }
@@ -340,13 +354,6 @@
   }
   services_.push_back(to_manage);
   SortServices();
-
-  vector<string> service_paths;
-  for (it = services_.begin(); it != services_.end(); ++it) {
-    service_paths.push_back((*it)->GetRpcIdentifier());
-  }
-  adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
-                                          service_paths);
 }
 
 void Manager::DeregisterService(const ServiceRefPtr &to_forget) {
@@ -406,6 +413,16 @@
 
 void Manager::SortServices() {
   sort(services_.begin(), services_.end(), ServiceSorter(technology_order_));
+
+  vector<string> service_paths;
+  vector<ServiceRefPtr>::iterator it;
+  for (it = services_.begin(); it != services_.end(); ++it) {
+    if ((*it)->IsVisible()) {
+      service_paths.push_back((*it)->GetRpcIdentifier());
+    }
+  }
+  adaptor_->EmitRpcIdentifierArrayChanged(flimflam::kServicesProperty,
+                                          service_paths);
 }
 
 string Manager::CalculateState(Error */*error*/) {
@@ -460,7 +477,7 @@
 // called via RPC (e.g., from ManagerDBusAdaptor)
 WiFiServiceRefPtr Manager::GetWifiService(const KeyValueStore &args,
                                           Error *error) {
-  std::vector<DeviceRefPtr> wifi_devices;
+  vector<DeviceRefPtr> wifi_devices;
   FilterByTechnology(Technology::kWifi, &wifi_devices);
   if (wifi_devices.empty()) {
     error->Populate(Error::kInvalidArguments, kManagerErrorNoDevice);