shill: fix DisableTechnology with multiple devices of a technology

For some Devices (e.g. Cellular), EnableTechnology and DisableTechnology are
asynchronous operations. Previously, shill would invoke the completion
callback for these operations, as each Device completed its work.
Unsurprisingly, this would fail on the second device.

Fix this by introducing ResultAggregator, which aggregates the results from
multiple asynchronous operations. Now, if the Devices process
EnableTechnology or DisableTechnology asynchronously, then we will return
only after the final Device has completed the request.

While there: merge the code for EnableTechnology and DisableTechnology,
since the methods were symmetric, but non-trivial.

Note that one ugly case remains: if one or more Devices fails immediately,
but others all succeed asynchronously, we will not report any failure.

BUG=chromium:258206
TEST=new unit tests, manual

Manual testing
--------------
- grab a device with two cellular modems (e.g. on-board and usb)
- disable cellular from the ash tray
  -> shill should not crash
- enable cellular from the ash tray
  -> shill should not crash

Change-Id: I09f94326342900e4cee6929d9edbe5cf735c92d7
Reviewed-on: https://gerrit.chromium.org/gerrit/62016
Commit-Queue: mukesh agrawal <quiche@chromium.org>
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Tested-by: mukesh agrawal <quiche@chromium.org>
diff --git a/dbus_adaptor.cc b/dbus_adaptor.cc
index a296ded..a85df19 100644
--- a/dbus_adaptor.cc
+++ b/dbus_adaptor.cc
@@ -478,14 +478,14 @@
 
 void DBusAdaptor::ReplyNow(const DBus::Tag *tag) {
   Continuation *cont = find_continuation(tag);
-  CHECK(cont);
+  CHECK(cont) << "Failed to find continuation.";
   return_now(cont);
 }
 
 template <typename T>
 void DBusAdaptor::TypedReplyNow(const DBus::Tag *tag, const T &value) {
   Continuation *cont = find_continuation(tag);
-  CHECK(cont);
+  CHECK(cont) << "Failed to find continuation.";
   cont->writer() << value;
   return_now(cont);
 }
@@ -493,7 +493,7 @@
 void DBusAdaptor::ReplyNowWithError(const DBus::Tag *tag,
                                     const DBus::Error &error) {
   Continuation *cont = find_continuation(tag);
-  CHECK(cont);
+  CHECK(cont) << "Failed to find continuation.";
   return_error(cont, error);
 }