[shill] Enable Profile objects to manage a list of Services to persist.

The Manager will hang on to a list of active services.  They will be sorted,
someday, in an order that makes sense.  Every service will be associated with
a Profile, though it may the an ephemeral profile that won't persist state to
disk.  Profiles will maintain a map of service name to service references to
track the services whose state they persist to disk.  Services may move between
Profiles, and will certainly need to be bound to one after they are registered
with the Manager, so support for this is provided as well.

BUG=chromium-os:17436
TEST=unit tests

Change-Id: Id43a0e1d97302b6f574bd2213d4f3d176bb5223f
Reviewed-on: http://gerrit.chromium.org/gerrit/4033
Reviewed-by: Chris Masone <cmasone@chromium.org>
Tested-by: Chris Masone <cmasone@chromium.org>
diff --git a/manager.cc b/manager.cc
index 820dba7..ce7a2a4 100644
--- a/manager.cc
+++ b/manager.cc
@@ -20,6 +20,7 @@
 #include "shill/default_profile.h"
 #include "shill/device.h"
 #include "shill/device_info.h"
+#include "shill/ephemeral_profile.h"
 #include "shill/error.h"
 #include "shill/profile.h"
 #include "shill/property_accessor.h"
@@ -36,7 +37,8 @@
   : adaptor_(control_interface->CreateManagerAdaptor(this)),
     device_info_(control_interface, dispatcher, this),
     modem_info_(control_interface, dispatcher, this, glib),
-    running_(false) {
+    running_(false),
+    ephemeral_profile_(new EphemeralProfile(control_interface, glib, this)) {
   HelpRegisterDerivedString(flimflam::kActiveProfileProperty,
                             &Manager::GetActiveProfileName,
                             NULL);
@@ -73,12 +75,20 @@
   // TODO(cmasone): Wire these up once we actually put in profile support.
   // known_properties_.push_back(flimflam::kProfilesProperty);
 
-  profiles_.push_back(new DefaultProfile(control_interface, glib, props_));
-
+  profiles_.push_back(new DefaultProfile(control_interface,
+                                         glib,
+                                         this,
+                                         props_));
   VLOG(2) << "Manager initialized.";
 }
 
-Manager::~Manager() {}
+Manager::~Manager() {
+  vector<ProfileRefPtr>::iterator it;
+  for (it = profiles_.begin(); it != profiles_.end(); ++it) {
+    (*it)->Finalize();
+  }
+  ephemeral_profile_->Finalize();
+}
 
 void Manager::Start() {
   LOG(INFO) << "Manager started.";
@@ -99,6 +109,12 @@
   return profiles_.back();
 }
 
+bool Manager::MoveToActiveProfile(const ProfileRefPtr &from,
+                                  const ServiceRefPtr &to_move) {
+  return ActiveProfile()->AdoptService(to_move) &&
+      from->AbandonService(to_move->UniqueName());
+}
+
 void Manager::RegisterDevice(const DeviceRefPtr &to_manage) {
   vector<DeviceRefPtr>::iterator it;
   for (it = devices_.begin(); it != devices_.end(); ++it) {
@@ -123,18 +139,30 @@
 }
 
 void Manager::RegisterService(const ServiceRefPtr &to_manage) {
+  // This should look for |to_manage| in the real profiles and, if found,
+  // do...something...to merge the meaningful state, I guess.
+
+  // If not found, add it to the ephemeral profile
+  ephemeral_profile_->AdoptService(to_manage);
+
+  // Now add to OUR list.
+  // TODO(cmasone): Keep this list sorted.
   vector<ServiceRefPtr>::iterator it;
   for (it = services_.begin(); it != services_.end(); ++it) {
-    if (to_manage.get() == it->get())
+    if (to_manage->UniqueName() == (*it)->UniqueName())
       return;
   }
   services_.push_back(to_manage);
 }
 
 void Manager::DeregisterService(const ServiceConstRefPtr &to_forget) {
+  // If the service is in the ephemeral profile, destroy it.
+  if (!ephemeral_profile_->AbandonService(to_forget->UniqueName())) {
+    // if it's in one of the real profiles...um...I guess mark it unconnectable?
+  }
   vector<ServiceRefPtr>::iterator it;
   for (it = services_.begin(); it != services_.end(); ++it) {
-    if (to_forget.get() == it->get()) {
+    if (to_forget->UniqueName() == (*it)->UniqueName()) {
       services_.erase(it);
       return;
     }
@@ -154,9 +182,8 @@
 ServiceRefPtr Manager::FindService(const std::string& name) {
   vector<ServiceRefPtr>::iterator it;
   for (it = services_.begin(); it != services_.end(); ++it) {
-    if (name == (*it)->UniqueName()) {
+    if (name == (*it)->UniqueName())
       return *it;
-    }
   }
   return NULL;
 }
@@ -208,8 +235,6 @@
 }
 
 vector<string> Manager::EnumerateAvailableServices() {
-  // TODO(cmasone): This should, instead, be returned by calling into the
-  // currently active profile.
   vector<string> service_rpc_ids;
   for (vector<ServiceRefPtr>::const_iterator it = services_.begin();
        it != services_.end();
@@ -220,7 +245,7 @@
 }
 
 vector<string> Manager::EnumerateWatchedServices() {
-  // TODO(cmasone): Implement this for real by querying the active profile.
+  // TODO(cmasone): Filter this list for services in appropriate states.
   return EnumerateAvailableServices();
 }