shill: reduce some copy-paste in dbus proxies

When making asynchronous D-Bus calls, we have to take
care not to leak Callback objects. This code occurs
in many places, but differs only in types.

Factor this code out into a template, to remove code
duplication.

CQ-DEPEND=CL:195761
BUG=chromium:365390
TEST=unit tests

Change-Id: Ica63045a00b9bbd70b3e12cb0939f0d7f1af0e1d
Reviewed-on: https://chromium-review.googlesource.com/195762
Tested-by: mukesh agrawal <quiche@chromium.org>
Reviewed-by: Ben Chan <benchan@chromium.org>
Commit-Queue: mukesh agrawal <quiche@chromium.org>
diff --git a/dbus_async_call_helper.h b/dbus_async_call_helper.h
new file mode 100644
index 0000000..aff6a38
--- /dev/null
+++ b/dbus_async_call_helper.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SHILL_DBUS_ASYNC_CALL_HELPER_H_
+#define SHILL_DBUS_ASYNC_CALL_HELPER_H_
+
+#include "shill/logging.h"
+
+#include <dbus-c++/error.h>
+
+#include "shill/error.h"
+
+namespace shill {
+
+// The dbus-c++ async call mechanism has a funny way of handling the
+// callback parameter. In particular, the caller is responsible for
+// cleaning up the callback. (This is unlike the low-level D-Bus
+// library, which accepts a function pointer for the cleanup
+// function.)
+//
+// In cases where the call completes asynchronously, we delete the
+// callback in the return-handling code. However, if the call
+// generates a synchronous error, we need to delete the callback
+// immediately.
+//
+// This template simply factors out that pattern, so that we don't
+// need to repeat the code in every async stub.
+
+template<
+    typename TraceMsgT, typename ProxyT, typename CallT,
+    typename CallbackT, typename... ArgTypes>
+void BeginAsyncDBusCall(const TraceMsgT &trace_msg, ProxyT &proxy,
+                        const CallT &call, const CallbackT &callback,
+                        Error *error,
+                        void(*error_converter)(const DBus::Error &, Error *),
+                        int timeout, ArgTypes... call_args) {
+  SLOG(DBus, 2) << trace_msg;
+  auto cb = make_scoped_ptr(new CallbackT(callback));
+  try {
+    (proxy.*call)(call_args..., cb.get(), timeout);
+    cb.release();
+  } catch (const DBus::Error &e) {
+    if (error)
+      error_converter(e, error);
+  }
+}
+
+}  // namespace shill
+
+#endif  // SHILL_DBUS_ASYNC_CALL_HELPER_H_
diff --git a/dbus_objectmanager_proxy.cc b/dbus_objectmanager_proxy.cc
index a2af6f4..091d64a 100644
--- a/dbus_objectmanager_proxy.cc
+++ b/dbus_objectmanager_proxy.cc
@@ -4,6 +4,7 @@
 #include "shill/dbus_objectmanager_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -21,15 +22,8 @@
     Error *error,
     const ManagedObjectsCallback &callback,
     int timeout) {
-  scoped_ptr<ManagedObjectsCallback> cb(new ManagedObjectsCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetManagedObjects(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetManagedObjectsAsync, callback,
+                     error, &CellularError::FromDBusError, timeout);
 }
 
 void DBusObjectManagerProxy::set_interfaces_added_callback(
diff --git a/dbus_service_proxy.cc b/dbus_service_proxy.cc
index fb9b896..774e869 100644
--- a/dbus_service_proxy.cc
+++ b/dbus_service_proxy.cc
@@ -4,8 +4,10 @@
 
 #include "shill/dbus_service_proxy.h"
 
+#include <base/strings/stringprintf.h>
 #include <chromeos/dbus/service_constants.h>
 
+#include "shill/dbus_async_call_helper.h"
 #include "shill/error.h"
 #include "shill/logging.h"
 
@@ -22,14 +24,9 @@
                                     Error *error,
                                     const StringCallback &callback,
                                     int timeout) {
-  SLOG(DBus, 2) << __func__ << "(" << name << ")";
-  scoped_ptr<StringCallback> cb(new StringCallback(callback));
-  try {
-    proxy_.GetNameOwner(name, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(base::StringPrintf("%s(%s)", __func__, name.c_str()),
+                     proxy_, &Proxy::GetNameOwnerAsync, callback,
+                     error, &FromDBusError, timeout, name);
 }
 
 void DBusServiceProxy::set_name_owner_changed_callback(
diff --git a/mm1_bearer_proxy.cc b/mm1_bearer_proxy.cc
index def64fc..3576c5b 100644
--- a/mm1_bearer_proxy.cc
+++ b/mm1_bearer_proxy.cc
@@ -5,6 +5,7 @@
 #include "shill/mm1_bearer_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -25,30 +26,16 @@
                           const ResultCallback &callback,
                           int timeout) {
   SLOG(Modem, 2) << __func__;
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Connect(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::ConnectAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout);
 }
 
 void BearerProxy::Disconnect(Error *error,
                              const ResultCallback &callback,
                              int timeout) {
   SLOG(Modem, 2) << __func__;
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Disconnect(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::DisconnectAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout);
 }
 
 BearerProxy::Proxy::Proxy(DBus::Connection *connection,
diff --git a/mm1_modem_location_proxy.cc b/mm1_modem_location_proxy.cc
index ddfa3d3..b3ca0c1 100644
--- a/mm1_modem_location_proxy.cc
+++ b/mm1_modem_location_proxy.cc
@@ -5,6 +5,7 @@
 #include "mm1_modem_location_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -25,31 +26,17 @@
                                const ResultCallback &callback,
                                int timeout) {
   SLOG(Modem, 2) << __func__;
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Setup(sources, signal_location, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::SetupAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout,
+                     sources, signal_location);
 }
 
 void ModemLocationProxy::GetLocation(Error *error,
                                      const DBusEnumValueMapCallback &callback,
                                      int timeout) {
   SLOG(Modem, 2) << __func__;
-  scoped_ptr<DBusEnumValueMapCallback> cb(
-      new DBusEnumValueMapCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetLocation(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetLocationAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout);
 }
 
 ModemLocationProxy::Proxy::Proxy(DBus::Connection *connection,
diff --git a/mm1_modem_modem3gpp_proxy.cc b/mm1_modem_modem3gpp_proxy.cc
index 155f4c3..c5966a2 100644
--- a/mm1_modem_modem3gpp_proxy.cc
+++ b/mm1_modem_modem3gpp_proxy.cc
@@ -5,6 +5,7 @@
 #include "shill/mm1_modem_modem3gpp_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -24,30 +25,16 @@
                                    Error *error,
                                    const ResultCallback &callback,
                                    int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Register(operator_id, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::RegisterAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout,
+                     operator_id);
 }
 
 void ModemModem3gppProxy::Scan(Error *error,
                                const DBusPropertyMapsCallback &callback,
                                int timeout) {
-  scoped_ptr<DBusPropertyMapsCallback> cb(
-      new DBusPropertyMapsCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Scan(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::ScanAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout);
 }
 
 // ModemModem3gppProxy::Proxy
diff --git a/mm1_modem_modemcdma_proxy.cc b/mm1_modem_modemcdma_proxy.cc
index c09bf96..ef5ae6a 100644
--- a/mm1_modem_modemcdma_proxy.cc
+++ b/mm1_modem_modemcdma_proxy.cc
@@ -5,6 +5,7 @@
 #include "shill/mm1_modem_modemcdma_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -23,15 +24,9 @@
                         Error *error,
                         const ResultCallback &callback,
                         int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Activate(carrier, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::ActivateAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout,
+                     carrier);
 }
 
 void ModemModemCdmaProxy::ActivateManual(
@@ -39,15 +34,9 @@
     Error *error,
     const ResultCallback &callback,
     int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.ActivateManual(properties, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::ActivateManualAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout,
+                     properties);
 }
 
 void ModemModemCdmaProxy::set_activation_state_callback(
diff --git a/mm1_modem_proxy.cc b/mm1_modem_proxy.cc
index d9772bd..017781d 100644
--- a/mm1_modem_proxy.cc
+++ b/mm1_modem_proxy.cc
@@ -7,6 +7,7 @@
 #include <ModemManager/ModemManager.h>
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -14,6 +15,15 @@
 namespace shill {
 namespace mm1 {
 
+template<typename TraceMsgT, typename CallT, typename CallbackT,
+         typename... ArgTypes>
+void ModemProxy::BeginCall(
+    const TraceMsgT &trace_msg, const CallT &call, CallbackT &callback,
+    Error *error, int timeout, ArgTypes... rest) {
+  BeginAsyncDBusCall(trace_msg, proxy_, call, callback, error,
+                     &CellularError::FromMM1DBusError, timeout, rest...);
+}
+
 ModemProxy::ModemProxy(DBus::Connection *connection,
                        const string &path,
                        const string &service)
@@ -31,15 +41,8 @@
                         const ResultCallback &callback,
                         int timeout) {
   SLOG(Modem, 2) << __func__ << "(" << enable << ", " << timeout << ")";
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Enable(enable, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::EnableAsync, callback, error, timeout,
+            enable);
 }
 
 void ModemProxy::CreateBearer(
@@ -47,74 +50,38 @@
     Error *error,
     const DBusPathCallback &callback,
     int timeout) {
-  scoped_ptr<DBusPathCallback> cb(new DBusPathCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.CreateBearer(properties, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::CreateBearerAsync, callback, error, timeout,
+            properties);
 }
 
 void ModemProxy::DeleteBearer(const ::DBus::Path &bearer,
                               Error *error,
                               const ResultCallback &callback,
                               int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.DeleteBearer(bearer, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::DeleteBearerAsync, callback, error, timeout,
+            bearer);
 }
 
 void ModemProxy::Reset(Error *error,
                        const ResultCallback &callback,
                        int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Reset(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::ResetAsync, callback, error, timeout);
 }
 
 void ModemProxy::FactoryReset(const std::string &code,
                               Error *error,
                               const ResultCallback &callback,
                               int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.FactoryReset(code, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::FactoryResetAsync, callback, error, timeout,
+            code);
 }
 
 void ModemProxy::SetCurrentCapabilities(const uint32_t &capabilities,
                                         Error *error,
                                         const ResultCallback &callback,
                                         int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.SetCurrentCapabilities(capabilities, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::SetCurrentCapabilitiesAsync, callback, error,
+            timeout, capabilities);
 }
 
 void ModemProxy::SetCurrentModes(
@@ -122,30 +89,16 @@
     Error *error,
     const ResultCallback &callback,
     int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.SetCurrentModes(modes, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::SetCurrentModesAsync, callback, error, timeout,
+            modes);
 }
 
 void ModemProxy::SetCurrentBands(const std::vector<uint32_t> &bands,
                                  Error *error,
                                  const ResultCallback &callback,
                                  int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.SetCurrentBands(bands, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::SetCurrentBandsAsync, callback, error, timeout,
+            bands);
 }
 
 void ModemProxy::Command(const std::string &cmd,
@@ -153,30 +106,16 @@
                          Error *error,
                          const StringCallback &callback,
                          int timeout) {
-  scoped_ptr<StringCallback> cb(new StringCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Command(cmd, user_timeout, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::CommandAsync, callback, error, timeout,
+            cmd, user_timeout);
 }
 
 void ModemProxy::SetPowerState(const uint32_t &power_state,
                                Error *error,
                                const ResultCallback &callback,
                                int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.SetPowerState(power_state, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::SetPowerStateAsync, callback, error, timeout,
+            power_state);
 }
 
 ModemProxy::Proxy::Proxy(DBus::Connection *connection,
diff --git a/mm1_modem_proxy.h b/mm1_modem_proxy.h
index e828b40..be9c458 100644
--- a/mm1_modem_proxy.h
+++ b/mm1_modem_proxy.h
@@ -115,6 +115,12 @@
 
   Proxy proxy_;
 
+  template<typename TraceMsgT, typename CallT, typename CallbackT,
+      typename... ArgTypes>
+      void BeginCall(
+          const TraceMsgT &trace_msg, const CallT &call, CallbackT &callback,
+          Error *error, int timeout, ArgTypes... rest);
+
   DISALLOW_COPY_AND_ASSIGN(ModemProxy);
 };
 
diff --git a/mm1_modem_simple_proxy.cc b/mm1_modem_simple_proxy.cc
index 4e4d781..5643237 100644
--- a/mm1_modem_simple_proxy.cc
+++ b/mm1_modem_simple_proxy.cc
@@ -5,6 +5,7 @@
 #include "shill/mm1_modem_simple_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -24,44 +25,25 @@
     Error *error,
     const DBusPathCallback &callback,
     int timeout) {
-  scoped_ptr<DBusPathCallback> cb(new DBusPathCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Connect(properties, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::ConnectAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout,
+                     properties);
 }
 
 void ModemSimpleProxy::Disconnect(const ::DBus::Path &bearer,
                                   Error *error,
                                   const ResultCallback &callback,
                                   int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Disconnect(bearer, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::DisconnectAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout,
+                     bearer);
 }
 
 void ModemSimpleProxy::GetStatus(Error *error,
                                  const DBusPropertyMapCallback &callback,
                                  int timeout) {
-  scoped_ptr<DBusPropertyMapCallback> cb(new DBusPropertyMapCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetStatus(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetStatusAsync, callback,
+                     error, &CellularError::FromMM1DBusError, timeout);
 }
 
 
diff --git a/mm1_modem_time_proxy.cc b/mm1_modem_time_proxy.cc
index 9ca58c1..a1895c4 100644
--- a/mm1_modem_time_proxy.cc
+++ b/mm1_modem_time_proxy.cc
@@ -5,6 +5,7 @@
 #include "shill/mm1_modem_time_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -28,15 +29,8 @@
                                     const StringCallback &callback,
                                     int timeout) {
   SLOG(Modem, 2) << __func__;
-  scoped_ptr<StringCallback> cb(new StringCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetNetworkTime(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetNetworkTimeAsync, callback,
+                     error,  &CellularError::FromMM1DBusError, timeout);
 }
 
 ModemTimeProxy::Proxy::Proxy(DBus::Connection *connection,
diff --git a/mm1_sim_proxy.cc b/mm1_sim_proxy.cc
index b9ff1d8..dd7eae9 100644
--- a/mm1_sim_proxy.cc
+++ b/mm1_sim_proxy.cc
@@ -5,6 +5,7 @@
 #include "shill/mm1_sim_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -12,6 +13,15 @@
 namespace shill {
 namespace mm1 {
 
+template<typename TraceMsgT, typename CallT, typename CallbackT,
+         typename... ArgTypes>
+void SimProxy::BeginCall(
+    const TraceMsgT &trace_msg, const CallT &call, CallbackT &callback,
+    Error *error, int timeout, ArgTypes... rest) {
+  BeginAsyncDBusCall(trace_msg, proxy_, call, callback, error,
+                     &CellularError::FromMM1DBusError, timeout, rest...);
+}
+
 SimProxy::SimProxy(DBus::Connection *connection,
                    const string &path,
                    const string &service)
@@ -26,15 +36,8 @@
                        int timeout) {
   // pin is intentionally not logged.
   SLOG(Modem, 2) << __func__ << "( XXX, " << timeout << ")";
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.SendPin(pin, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::SendPinAsync, callback, error, timeout,
+            pin);
 }
 
 void SimProxy::SendPuk(const string &puk,
@@ -44,15 +47,8 @@
                        int timeout) {
   // pin and puk are intentionally not logged.
   SLOG(Modem, 2) << __func__ << "( XXX, XXX, " << timeout << ")";
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.SendPuk(puk, pin, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::SendPukAsync, callback, error, timeout,
+            puk, pin);
 }
 
 void SimProxy::EnablePin(const string &pin,
@@ -62,15 +58,8 @@
                          int timeout) {
   // pin is intentionally not logged.
   SLOG(Modem, 2) << __func__ << "( XXX, " << enabled << ", " << timeout << ")";
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.EnablePin(pin, enabled, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::EnablePinAsync, callback, error, timeout,
+            pin, enabled);
 }
 
 void SimProxy::ChangePin(const string &old_pin,
@@ -80,15 +69,8 @@
                          int timeout) {
   // old_pin and new_pin are intentionally not logged.
   SLOG(Modem, 2) << __func__ << "( XXX, XXX, " << timeout << ")";
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.ChangePin(old_pin, new_pin, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromMM1DBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::ChangePinAsync, callback, error, timeout,
+            old_pin, new_pin);
 }
 
 SimProxy::Proxy::Proxy(DBus::Connection *connection,
diff --git a/mm1_sim_proxy.h b/mm1_sim_proxy.h
index ed2d3f4..2df1ffd 100644
--- a/mm1_sim_proxy.h
+++ b/mm1_sim_proxy.h
@@ -71,6 +71,12 @@
 
   Proxy proxy_;
 
+  template<typename TraceMsgT, typename CallT, typename CallbackT,
+      typename... ArgTypes>
+      void BeginCall(
+          const TraceMsgT &trace_msg, const CallT &call, CallbackT &callback,
+          Error *error, int timeout, ArgTypes... rest);
+
   DISALLOW_COPY_AND_ASSIGN(SimProxy);
 };
 
diff --git a/modem_cdma_proxy.cc b/modem_cdma_proxy.cc
index 0656474..b250705 100644
--- a/modem_cdma_proxy.cc
+++ b/modem_cdma_proxy.cc
@@ -5,6 +5,7 @@
 #include "shill/modem_cdma_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/logging.h"
 
 using std::string;
@@ -22,46 +23,24 @@
 void ModemCDMAProxy::Activate(const string &carrier, Error *error,
                               const ActivationResultCallback &callback,
                               int timeout) {
-  scoped_ptr<ActivationResultCallback>
-      cb(new ActivationResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Activate(carrier, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::ActivateAsync, callback,
+                     error, &CellularError::FromDBusError, timeout,
+                     carrier);
 }
 
 void ModemCDMAProxy::GetRegistrationState(
     Error *error,
     const RegistrationStateCallback &callback,
     int timeout) {
-  scoped_ptr<RegistrationStateCallback>
-      cb(new RegistrationStateCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetRegistrationState(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetRegistrationStateAsync,
+                     callback, error, &CellularError::FromDBusError, timeout);
 }
 
 void ModemCDMAProxy::GetSignalQuality(Error *error,
                                       const SignalQualityCallback &callback,
                                       int timeout) {
-  scoped_ptr<SignalQualityCallback> cb(new SignalQualityCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetSignalQuality(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetSignalQualityAsync, callback,
+                     error, &CellularError::FromDBusError, timeout);
 }
 
 const string ModemCDMAProxy::MEID() {
diff --git a/modem_gobi_proxy.cc b/modem_gobi_proxy.cc
index 7612d8c..271a620 100644
--- a/modem_gobi_proxy.cc
+++ b/modem_gobi_proxy.cc
@@ -7,6 +7,7 @@
 #include <base/bind.h>
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/error.h"
 #include "shill/logging.h"
 
@@ -27,16 +28,9 @@
                                 Error *error,
                                 const ResultCallback &callback,
                                 int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.SetCarrier(carrier, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error) {
-      CellularError::FromDBusError(e, error);
-    }
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::SetCarrierAsync, callback,
+                     error, &CellularError::FromDBusError, timeout,
+                     carrier);
 }
 
 ModemGobiProxy::Proxy::Proxy(DBus::Connection *connection,
diff --git a/modem_gsm_card_proxy.cc b/modem_gsm_card_proxy.cc
index 1633fb4..a4277cb 100644
--- a/modem_gsm_card_proxy.cc
+++ b/modem_gsm_card_proxy.cc
@@ -7,6 +7,7 @@
 #include <base/bind.h>
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/error.h"
 #include "shill/logging.h"
 
@@ -16,6 +17,15 @@
 
 namespace shill {
 
+template<typename TraceMsgT, typename CallT, typename CallbackT,
+         typename... ArgTypes>
+void ModemGSMCardProxy::BeginCall(
+    const TraceMsgT &trace_msg, const CallT &call, CallbackT &callback,
+    Error *error, int timeout, ArgTypes... rest) {
+  BeginAsyncDBusCall(trace_msg, proxy_, call, callback, error,
+                     &CellularError::FromDBusError, timeout, rest...);
+}
+
 ModemGSMCardProxy::ModemGSMCardProxy(DBus::Connection *connection,
                                      const string &path,
                                      const string &service)
@@ -26,102 +36,49 @@
 void ModemGSMCardProxy::GetIMEI(Error *error,
                                 const GSMIdentifierCallback &callback,
                                 int timeout) {
-  scoped_ptr<GSMIdentifierCallback> cb(new GSMIdentifierCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetImei(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::GetImeiAsync, callback, error, timeout);
 }
 
 void ModemGSMCardProxy::GetIMSI(Error *error,
                                 const GSMIdentifierCallback &callback,
                                 int timeout) {
-  scoped_ptr<GSMIdentifierCallback> cb(new GSMIdentifierCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetImsi(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::GetImsiAsync, callback, error, timeout);
 }
 
 void ModemGSMCardProxy::GetSPN(Error *error,
                                const GSMIdentifierCallback &callback,
                                int timeout) {
-  scoped_ptr<GSMIdentifierCallback> cb(new GSMIdentifierCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetSpn(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::GetSpnAsync, callback, error, timeout);
 }
 
 void ModemGSMCardProxy::GetMSISDN(Error *error,
                                   const GSMIdentifierCallback &callback,
                                   int timeout) {
-  scoped_ptr<GSMIdentifierCallback> cb(new GSMIdentifierCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetMsIsdn(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::GetMsIsdnAsync, callback, error, timeout);
 }
 
 void ModemGSMCardProxy::EnablePIN(const string &pin, bool enabled,
                                   Error *error,
                                   const ResultCallback &callback,
                                   int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.EnablePin(pin, enabled, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::EnablePinAsync, callback, error, timeout,
+            pin, enabled);
 }
 
 void ModemGSMCardProxy::SendPIN(const string &pin,
                                 Error *error,
                                 const ResultCallback &callback,
                                 int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.SendPin(pin, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::SendPinAsync, callback, error, timeout,
+            pin);
 }
 
 void ModemGSMCardProxy::SendPUK(const string &puk, const string &pin,
                                 Error *error,
                                 const ResultCallback &callback,
                                 int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.SendPuk(puk, pin, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::SendPukAsync, callback, error, timeout,
+            puk, pin);
 }
 
 void ModemGSMCardProxy::ChangePIN(const string &old_pin,
@@ -129,15 +86,8 @@
                                   Error *error,
                                   const ResultCallback &callback,
                                   int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.ChangePin(old_pin, new_pin, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginCall(__func__, &Proxy::ChangePinAsync, callback, error, timeout,
+            old_pin, new_pin);
 }
 
 uint32 ModemGSMCardProxy::EnabledFacilityLocks() {
diff --git a/modem_gsm_card_proxy.h b/modem_gsm_card_proxy.h
index fdfb515..d238de2 100644
--- a/modem_gsm_card_proxy.h
+++ b/modem_gsm_card_proxy.h
@@ -85,6 +85,12 @@
 
   Proxy proxy_;
 
+  template<typename TraceMsgT, typename CallT, typename CallbackT,
+      typename... ArgTypes>
+      void BeginCall(
+          const TraceMsgT &trace_msg, const CallT &call, CallbackT &callback,
+          Error *error, int timeout, ArgTypes... rest);
+
   DISALLOW_COPY_AND_ASSIGN(ModemGSMCardProxy);
 };
 
diff --git a/modem_gsm_network_proxy.cc b/modem_gsm_network_proxy.cc
index 8fdb9e9..7d19a2b 100644
--- a/modem_gsm_network_proxy.cc
+++ b/modem_gsm_network_proxy.cc
@@ -5,6 +5,7 @@
 #include "shill/modem_gsm_network_proxy.h"
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/error.h"
 #include "shill/logging.h"
 
@@ -25,60 +26,32 @@
     Error *error,
     const RegistrationInfoCallback &callback,
     int timeout) {
-  scoped_ptr<RegistrationInfoCallback>
-      cb(new RegistrationInfoCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetRegistrationInfo(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetRegistrationInfoAsync,
+                     callback, error, &CellularError::FromDBusError, timeout);
 }
 
 void ModemGSMNetworkProxy::GetSignalQuality(
     Error *error,
     const SignalQualityCallback &callback,
     int timeout) {
-  scoped_ptr<SignalQualityCallback> cb(new SignalQualityCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetSignalQuality(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetSignalQualityAsync, callback,
+                     error, &CellularError::FromDBusError, timeout);
 }
 
 void ModemGSMNetworkProxy::Register(const string &network_id,
                                     Error *error,
                                     const ResultCallback &callback,
                                     int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Register(network_id, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::RegisterAsync, callback,
+                     error, &CellularError::FromDBusError, timeout,
+                     network_id);
 }
 
 void ModemGSMNetworkProxy::Scan(Error *error,
                                 const ScanResultsCallback &callback,
                                 int timeout) {
-  scoped_ptr<ScanResultsCallback> cb(new ScanResultsCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Scan(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::ScanAsync, callback,
+                     error, &CellularError::FromDBusError, timeout);
 }
 
 uint32 ModemGSMNetworkProxy::AccessTechnology() {
diff --git a/modem_proxy.cc b/modem_proxy.cc
index b904472..8c409bd 100644
--- a/modem_proxy.cc
+++ b/modem_proxy.cc
@@ -7,6 +7,7 @@
 #include <base/bind.h>
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/error.h"
 #include "shill/logging.h"
 
@@ -34,42 +35,22 @@
 void ModemProxy::Enable(bool enable, Error *error,
                         const ResultCallback &callback, int timeout) {
   SLOG(Modem, 2) << __func__ << "(" << enable << ", " << timeout << ")";
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Enable(enable, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::EnableAsync, callback,
+                     error, &CellularError::FromDBusError, timeout,
+                     enable);
 }
 
 void ModemProxy::Disconnect(Error *error, const ResultCallback &callback,
                             int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Disconnect(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::DisconnectAsync, callback,
+                     error, &CellularError::FromDBusError, timeout);
 }
 
 void ModemProxy::GetModemInfo(Error *error,
                               const ModemInfoCallback &callback,
                               int timeout) {
-  scoped_ptr<ModemInfoCallback> cb(new ModemInfoCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetInfo(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetInfoAsync, callback,
+                     error, &CellularError::FromDBusError, timeout);
 }
 
 ModemProxy::Proxy::Proxy(DBus::Connection *connection,
diff --git a/modem_simple_proxy.cc b/modem_simple_proxy.cc
index 30b4bbd..57a3aa5 100644
--- a/modem_simple_proxy.cc
+++ b/modem_simple_proxy.cc
@@ -7,6 +7,7 @@
 #include <base/bind.h>
 
 #include "shill/cellular_error.h"
+#include "shill/dbus_async_call_helper.h"
 #include "shill/error.h"
 #include "shill/logging.h"
 
@@ -29,30 +30,17 @@
 void ModemSimpleProxy::GetModemStatus(Error *error,
                                       const DBusPropertyMapCallback &callback,
                                       int timeout) {
-  scoped_ptr<DBusPropertyMapCallback> cb(new DBusPropertyMapCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.GetStatus(cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::GetStatusAsync, callback,
+                     error, &CellularError::FromDBusError, timeout);
 }
 
 void ModemSimpleProxy::Connect(const DBusPropertiesMap &properties,
                                Error *error,
                                const ResultCallback &callback,
                                int timeout) {
-  scoped_ptr<ResultCallback> cb(new ResultCallback(callback));
-  try {
-    SLOG(DBus, 2) << __func__;
-    proxy_.Connect(properties, cb.get(), timeout);
-    cb.release();
-  } catch (const DBus::Error &e) {
-    if (error)
-      CellularError::FromDBusError(e, error);
-  }
+  BeginAsyncDBusCall(__func__, proxy_, &Proxy::ConnectAsync, callback,
+                     error, &CellularError::FromDBusError, timeout,
+                     properties);
 }
 
 ModemSimpleProxy::Proxy::Proxy(DBus::Connection *connection,