Add async support for shill client calls.

Many of the modem manager method invocations performed by the
shill cellular support have been converted to be asynchronous,
based on the dbus-c++ support for asynchronous proxies.
I've also hooked this up with the mechanism that was recently
introduced that allows adaptor methods to defer returning
results to callers of shill methods, so that we now have
an end-to-end asynchronous solution.

Adaptor methods that want to be non-blocking create a Returner
object, which will later be used to send back the result
of the operation. The cellular device code that implements
the method (or the cellular service code, depending on the
method), wraps the Returner in an AsyncCallHandler object,
which is passed to the proxy methods as the "data" argument.
When the reply callback for the method occurs, it can pull
the Returner object out of the AsyncCallHandler and use it
to return the result.

In the case of an operation like Enable that involves multiple
client method invocations, the object that wraps the returner
is a MultiStepAsyncCallHandler, a subclass of AsyncCallHandler,
that also wraps a list of Tasks comprising the compound
operation.

In either case, a callback indicates that the handling of
the method is complete by calling Complete() on the AsyncCallHandler.
This is an overloaded method - without any argument, it returns
a success result to the caller of the shill method. With an
Error argument, it returns the DBus::Error equivalent of that
error to the caller. For a MultiStepAsyncCallHandler, calling
Complete() with no argument removes the next Task from the
list and posts it to the main loop, unless there are no
remaining tasks, in which case it returns the result to
the caller of the original shill method.

I've converted the following operations to work asynchronously
end-to-end:
Enable, Register, EnterPIN, RequirePIN, ChangePIN, UnblockPIN,
Activate.
Connect and Scan have been changed to be asynchronous on the
proxy side, but not yet on the adaptor side. For Enable, all of
the individual proxy operations are now done asynchronously,
except for fetching of individual properties.

I've moved all the ModemProxy and ModemSimpleProxy method
invocations from Cellular into CellularCapability. Now all
operations to the modem are done through a Capability interface.

There is a memory leak issue noted in the file async_call_handler.h

BUG=chromium-os:23433,chromium-os:22732
TEST=unit tests, testing on device

Change-Id: I54254dd36d116a1e9089bc9b1a60fa06a3098bd5
Reviewed-on: https://gerrit.chromium.org/gerrit/12564
Commit-Ready: Eric Shienbrood <ers@chromium.org>
Reviewed-by: Eric Shienbrood <ers@chromium.org>
Tested-by: Eric Shienbrood <ers@chromium.org>
diff --git a/cellular_capability.h b/cellular_capability.h
index cf0f848..da5c5ee 100644
--- a/cellular_capability.h
+++ b/cellular_capability.h
@@ -8,8 +8,16 @@
 #include <string>
 
 #include <base/basictypes.h>
+#include <base/memory/scoped_ptr.h>
+#include <base/memory/scoped_vector.h>
+#include <gtest/gtest_prod.h>  // for FRIEND_TEST
 
+#include "shill/async_call_handler.h"
 #include "shill/dbus_properties.h"
+#include "shill/modem_proxy_interface.h"
+#include "shill/modem_simple_proxy_interface.h"
+
+class Task;
 
 namespace shill {
 
@@ -17,23 +25,28 @@
 class Error;
 class EventDispatcher;
 class ProxyFactory;
-class ReturnerInterface;
 
-// Cellular devices instantiate subclasses of CellularCapability that handle the
-// specific modem technologies and capabilities.
-class CellularCapability {
+// Cellular devices instantiate subclasses of CellularCapability that
+// handle the specific modem technologies and capabilities.
+class CellularCapability : public ModemProxyDelegate,
+                           public ModemSimpleProxyDelegate {
  public:
+  static const int kTimeoutActivate;
+  static const int kTimeoutConnect;
+  static const int kTimeoutDefault;
+  static const int kTimeoutRegister;
+  static const int kTimeoutScan;
+
+  static const char kConnectPropertyPhoneNumber[];
+  static const char kPropertyIMSI[];
+
+
   // |cellular| is the parent Cellular device.
-  CellularCapability(Cellular *cellular);
+  CellularCapability(Cellular *cellular, ProxyFactory *proxy_factory);
   virtual ~CellularCapability();
 
   Cellular *cellular() const { return cellular_; }
   ProxyFactory *proxy_factory() const { return proxy_factory_; }
-  EventDispatcher *dispatcher() const;
-
-  // Invoked on starting and stopping the cellular device.
-  virtual void OnDeviceStarted() = 0;
-  virtual void OnDeviceStopped() = 0;
 
   // Invoked by the parent Cellular device when a new service is created.
   virtual void OnServiceCreated() = 0;
@@ -42,40 +55,60 @@
 
   virtual void SetupConnectProperties(DBusPropertiesMap *properties) = 0;
 
-  // Activates the modem. Populates |error| on failure, leaves it unchanged
-  // otherwise. The default implementation fails by populating |error|.
-  virtual void Activate(const std::string &carrier, Error *error);
+  bool allow_roaming() const { return allow_roaming_; }
+
+  // StartModem attempts to put the modem in a state in which it is
+  // usable for creating services and establishing connections (if
+  // network conditions permit). It potentially consists of multiple
+  // non-blocking calls to the modem-manager server. After each call,
+  // control is passed back up to the main loop. Each time a reply to
+  // a non-blocking call is received, the operation advances to the next
+  // step, until either an error occurs in one of them, or all the steps
+  // have been completed, at which point StartModem() is finished.
+  virtual void StartModem();
+  virtual void StopModem();
+  // EnableModem ensures that the modem device is powered.
+  virtual void EnableModem(AsyncCallHandler *call_handler);
+  virtual void DisableModem(AsyncCallHandler *call_handler);
+  virtual void GetModemStatus(AsyncCallHandler *call_handler);
+  virtual void GetModemInfo(AsyncCallHandler *call_handler);
+  virtual void Connect(const DBusPropertiesMap &properties);
+  virtual void Disconnect();
+
+  // Activates the modem. Returns an Error on failure.
+  // The default implementation fails by returning a kNotSupported error
+  // to the caller.
+  virtual void Activate(const std::string &carrier,
+                        AsyncCallHandler *call_handler);
 
   // Network registration.
-  virtual void Register();
-  virtual void RegisterOnNetwork(const std::string &network_id, Error *error);
+  virtual void RegisterOnNetwork(const std::string &network_id,
+                                 AsyncCallHandler *call_handler);
   virtual bool IsRegistered() = 0;
 
-  // Retrieves identifiers associated with the modem and the capability.
-  virtual void GetIdentifiers() = 0;
-
-  virtual void GetProperties() = 0;
+  virtual void GetProperties(AsyncCallHandler *call_handler) = 0;
 
   // Retrieves the current cellular signal strength.
   virtual void GetSignalQuality() = 0;
 
-  virtual void GetRegistrationState() = 0;
+  virtual void GetRegistrationState(AsyncCallHandler *call_handler) = 0;
 
   virtual std::string CreateFriendlyServiceName() = 0;
 
   // PIN management. The default implementation fails by returning an error.
   virtual void RequirePIN(
-      const std::string &pin, bool require, ReturnerInterface *returner);
-  virtual void EnterPIN(const std::string &pin, ReturnerInterface *returner);
+      const std::string &pin, bool require, AsyncCallHandler *call_handler);
+  virtual void EnterPIN(const std::string &pin, AsyncCallHandler *call_handler);
   virtual void UnblockPIN(const std::string &unblock_code,
                           const std::string &pin,
-                          ReturnerInterface *returner);
+                          AsyncCallHandler *call_handler);
   virtual void ChangePIN(const std::string &old_pin,
                          const std::string &new_pin,
-                         ReturnerInterface *returner);
+                         AsyncCallHandler *call_handler);
 
-  // Network scanning. The default implementation fails by populating |error|.
-  virtual void Scan(Error *error);
+  // Network scanning. The default implementation fails by invoking
+  // the reply handler with an error.
+  virtual void Scan(AsyncCallHandler *call_handler);
 
   // Returns an empty string if the network technology is unknown.
   virtual std::string GetNetworkTechnologyString() const = 0;
@@ -85,12 +118,87 @@
   virtual void OnModemManagerPropertiesChanged(
       const DBusPropertiesMap &properties) = 0;
 
+  // Method and signal callbacks inherited from ModemProxyDelegate.
+  virtual void OnModemStateChanged(
+      uint32 old_state, uint32 new_state, uint32 reason);
+  virtual void OnModemEnableCallback(const Error &error,
+                                     AsyncCallHandler *call_handler);
+  virtual void OnGetModemInfoCallback(const ModemHardwareInfo &info,
+                                      const Error &error,
+                                      AsyncCallHandler *call_handler);
+
+  // Method and signal callbacks inherited from ModemSimpleProxyDelegate.
+  virtual void OnGetModemStatusCallback(const DBusPropertiesMap &props,
+                                        const Error &error,
+                                        AsyncCallHandler *call_handler);
+  virtual void OnConnectCallback(const Error &error,
+                                 AsyncCallHandler *call_handler);
+  virtual void OnDisconnectCallback(const Error &error,
+                                    AsyncCallHandler *call_handler);
+
+ protected:
+  class MultiStepAsyncCallHandler : public AsyncCallHandler {
+   public:
+    explicit MultiStepAsyncCallHandler(EventDispatcher *dispatcher);
+    virtual ~MultiStepAsyncCallHandler();
+
+    // Override the non-error case
+    virtual bool CompleteOperation();
+
+    void AddTask(Task *task);
+    void PostNextTask();
+
+   private:
+    EventDispatcher *dispatcher_;
+    ScopedVector<Task> tasks_;
+
+    DISALLOW_COPY_AND_ASSIGN(MultiStepAsyncCallHandler);
+  };
+
+  static void CompleteOperation(AsyncCallHandler *reply_handler);
+  static void CompleteOperation(AsyncCallHandler *reply_handler,
+                                const Error &error);
+  // Generic synthetic callback by which a Capability class can indicate
+  // that a requested operation is not supported.
+  void static OnUnsupportedOperation(const char *operation,
+                                     AsyncCallHandler *call_handler);
+
+  // Properties
+  bool allow_roaming_;
+  std::string carrier_;
+  std::string meid_;
+  std::string imei_;
+  std::string imsi_;
+  std::string esn_;
+  std::string mdn_;
+  std::string min_;
+  std::string model_id_;
+  std::string manufacturer_;
+  std::string firmware_revision_;
+  std::string hardware_revision_;
+
  private:
   friend class CellularTest;
+  friend class CellularCapabilityTest;
+  FRIEND_TEST(CellularCapabilityGSMTest, UpdateStatus);
+  FRIEND_TEST(CellularCapabilityTest, GetModemInfo);
+  FRIEND_TEST(CellularCapabilityTest, GetModemStatus);
+  FRIEND_TEST(CellularServiceTest, FriendlyName);
+  FRIEND_TEST(CellularTest, StartCDMARegister);
+  FRIEND_TEST(CellularTest, StartConnected);
+  FRIEND_TEST(CellularTest, StartGSMRegister);
+  FRIEND_TEST(CellularTest, StartLinked);
+  FRIEND_TEST(CellularTest, Connect);
+  FRIEND_TEST(CellularTest, DisconnectModem);
 
   Cellular *cellular_;
+
+  // Store cached copies of singletons for speed/ease of testing.
   ProxyFactory *proxy_factory_;
 
+  scoped_ptr<ModemProxyInterface> proxy_;
+  scoped_ptr<ModemSimpleProxyInterface> simple_proxy_;
+
   DISALLOW_COPY_AND_ASSIGN(CellularCapability);
 };