binder: Implement the callback addition/removal
BinderManager stores all the callback binder references registered via the
corresponding binder object.
The callbacks are deleted when either:
a. binder object death notification or
b. corresponding binder object is removed (for ex: all |wlan0| iface callbacks
are removed when the |wlan0| iface is deregistered).
Uses a helper class |CallbackObjectDeathNotifier| to cleanup the binder
references from our list when the hosting process is dead.
BUG: 30093041
Change-Id: Ib3f6817fc4d63e4f4711fe6aa280547b768bf774
Signed-off-by: Roshan Pius <rpius@google.com>
diff --git a/wpa_supplicant/binder/binder_manager.cpp b/wpa_supplicant/binder/binder_manager.cpp
index bc6c556..f9ed805 100644
--- a/wpa_supplicant/binder/binder_manager.cpp
+++ b/wpa_supplicant/binder/binder_manager.cpp
@@ -7,6 +7,8 @@
* See README for more details.
*/
+#include <algorithm>
+
#include <binder/IServiceManager.h>
#include "binder_manager.h"
@@ -40,6 +42,7 @@
// Create the main binder service object and register with system
// ServiceManager.
supplicant_object_ = new Supplicant(global);
+
android::String16 service_name(binder_constants::kServiceName);
android::defaultServiceManager()->addService(
service_name, android::IInterface::asBinder(supplicant_object_));
@@ -69,6 +72,9 @@
if (!iface_object_map_[ifname].get())
return 1;
+ // Initialize the vector of callbacks for this object.
+ iface_callbacks_map_[ifname] =
+ std::vector<android::sp<fi::w1::wpa_supplicant::IIfaceCallback>>();
return 0;
}
@@ -85,11 +91,28 @@
return 1;
const std::string ifname(wpa_s->ifname);
+
if (iface_object_map_.find(ifname) == iface_object_map_.end())
return 1;
- /* Delete the corresponding iface object from our map. */
+ // Delete the corresponding iface object from our map.
iface_object_map_.erase(ifname);
+
+ // Delete all callbacks registered for this object.
+ auto iface_callback_map_iter = iface_callbacks_map_.find(ifname);
+ if (iface_callback_map_iter == iface_callbacks_map_.end())
+ return 1;
+ const auto &iface_callback_list = iface_callback_map_iter->second;
+ for (const auto &callback : iface_callback_list) {
+ if (android::IInterface::asBinder(callback)->unlinkToDeath(
+ nullptr, callback.get()) != android::OK) {
+ wpa_printf(
+ MSG_ERROR,
+ "Error deregistering for death notification for "
+ "iface callback object");
+ }
+ }
+ iface_callbacks_map_.erase(iface_callback_map_iter);
return 0;
}
@@ -120,6 +143,9 @@
if (!network_object_map_[network_key].get())
return 1;
+ // Initialize the vector of callbacks for this object.
+ network_callbacks_map_[network_key] = std::vector<
+ android::sp<fi::w1::wpa_supplicant::INetworkCallback>>();
return 0;
}
@@ -145,13 +171,31 @@
if (network_object_map_.find(network_key) == network_object_map_.end())
return 1;
- /* Delete the corresponding network object from our map. */
+ // Delete the corresponding network object from our map.
network_object_map_.erase(network_key);
+
+ // Delete all callbacks registered for this object.
+ auto network_callback_map_iter =
+ network_callbacks_map_.find(network_key);
+ if (network_callback_map_iter == network_callbacks_map_.end())
+ return 1;
+ const auto &network_callback_list = network_callback_map_iter->second;
+ for (const auto &callback : network_callback_list) {
+ if (android::IInterface::asBinder(callback)->unlinkToDeath(
+ nullptr, callback.get()) != android::OK) {
+ wpa_printf(
+ MSG_ERROR, "Error deregistering for death "
+ "notification for "
+ "network callback object");
+ }
+ }
+ network_callbacks_map_.erase(network_callback_map_iter);
return 0;
}
/**
- * Retrieve the |IIface| binder object reference using the provided ifname.
+ * Retrieve the |IIface| binder object reference using the provided
+ * ifname.
*
* @param ifname Name of the corresponding interface.
* @param iface_object Binder reference corresponding to the iface.
@@ -165,16 +209,17 @@
if (ifname.empty() || !iface_object)
return 1;
- if (iface_object_map_.find(ifname) == iface_object_map_.end())
+ auto iface_object_iter = iface_object_map_.find(ifname);
+ if (iface_object_iter == iface_object_map_.end())
return 1;
- *iface_object = iface_object_map_[ifname];
+ *iface_object = iface_object_iter->second;
return 0;
}
/**
- * Retrieve the |INetwork| binder object reference using the provided ifname
- * and network_id.
+ * Retrieve the |INetwork| binder object reference using the provided
+ * ifname and network_id.
*
* @param ifname Name of the corresponding interface.
* @param network_id ID of the corresponding network.
@@ -193,10 +238,11 @@
const std::string network_key =
getNetworkObjectMapKey(ifname, network_id);
- if (network_object_map_.find(network_key) == network_object_map_.end())
+ auto network_object_iter = network_object_map_.find(network_key);
+ if (network_object_iter == network_object_map_.end())
return 1;
- *network_object = network_object_map_[network_key];
+ *network_object = network_object_iter->second;
return 0;
}
@@ -211,7 +257,13 @@
int BinderManager::addSupplicantCallbackBinderObject(
const android::sp<fi::w1::wpa_supplicant::ISupplicantCallback> &callback)
{
- return 0;
+ // Register for death notification before we add it to our list.
+ auto on_binder_died_fctor = std::bind(
+ &BinderManager::removeSupplicantCallbackBinderObject, this,
+ std::placeholders::_1);
+ return registerForDeathAndAddCallbackBinderObjectToList<
+ fi::w1::wpa_supplicant::ISupplicantCallback>(
+ callback, on_binder_died_fctor, supplicant_callbacks_);
}
/**
* Add a new |IIfaceCallback| binder object reference to our
@@ -226,7 +278,21 @@
const std::string &ifname,
const android::sp<fi::w1::wpa_supplicant::IIfaceCallback> &callback)
{
- return 0;
+ if (ifname.empty())
+ return 1;
+
+ auto iface_callback_map_iter = iface_callbacks_map_.find(ifname);
+ if (iface_callback_map_iter == iface_callbacks_map_.end())
+ return 1;
+ auto &iface_callback_list = iface_callback_map_iter->second;
+
+ // Register for death notification before we add it to our list.
+ auto on_binder_died_fctor = std::bind(
+ &BinderManager::removeIfaceCallbackBinderObject, this, ifname,
+ std::placeholders::_1);
+ return registerForDeathAndAddCallbackBinderObjectToList<
+ fi::w1::wpa_supplicant::IIfaceCallback>(
+ callback, on_binder_died_fctor, iface_callback_list);
}
/**
@@ -243,13 +309,30 @@
const std::string &ifname, int network_id,
const android::sp<fi::w1::wpa_supplicant::INetworkCallback> &callback)
{
- return 0;
+ if (ifname.empty() || network_id < 0)
+ return 1;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(ifname, network_id);
+ auto network_callback_map_iter =
+ network_callbacks_map_.find(network_key);
+ if (network_callback_map_iter == network_callbacks_map_.end())
+ return 1;
+ auto &network_callback_list = network_callback_map_iter->second;
+
+ // Register for death notification before we add it to our list.
+ auto on_binder_died_fctor = std::bind(
+ &BinderManager::removeNetworkCallbackBinderObject, this, ifname,
+ network_id, std::placeholders::_1);
+ return registerForDeathAndAddCallbackBinderObjectToList<
+ fi::w1::wpa_supplicant::INetworkCallback>(
+ callback, on_binder_died_fctor, network_callback_list);
}
/**
* Creates a unique key for the network using the provided |ifname| and
- * |network_id| to be used
- * in the internal map of |INetwork| objects.
+ * |network_id| to be used in the internal map of |INetwork| objects.
* This is of the form |ifname|_|network_id|. For ex: "wlan0_1".
*
* @param ifname Name of the corresponding interface.
@@ -260,4 +343,115 @@
{
return ifname + "_" + std::to_string(network_id);
}
+
+/**
+ * Removes the provided |ISupplicantCallback| binder object reference
+ * from our global callback list.
+ *
+ * @param callback Binder reference of the |ISupplicantCallback| object.
+ */
+void BinderManager::removeSupplicantCallbackBinderObject(
+ const android::sp<fi::w1::wpa_supplicant::ISupplicantCallback> &callback)
+{
+ supplicant_callbacks_.erase(
+ std::remove(
+ supplicant_callbacks_.begin(), supplicant_callbacks_.end(),
+ callback),
+ supplicant_callbacks_.end());
+}
+
+/**
+ * Removes the provided |IIfaceCallback| binder object reference from
+ * our interface callback list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param callback Binder reference of the |IIfaceCallback| object.
+ */
+void BinderManager::removeIfaceCallbackBinderObject(
+ const std::string &ifname,
+ const android::sp<fi::w1::wpa_supplicant::IIfaceCallback> &callback)
+{
+ if (ifname.empty())
+ return;
+
+ auto iface_callback_map_iter = iface_callbacks_map_.find(ifname);
+ if (iface_callback_map_iter == iface_callbacks_map_.end())
+ return;
+
+ auto &iface_callback_list = iface_callback_map_iter->second;
+ iface_callback_list.erase(
+ std::remove(
+ iface_callback_list.begin(), iface_callback_list.end(),
+ callback),
+ iface_callback_list.end());
+}
+
+/**
+ * Removes the provided |INetworkCallback| binder object reference from
+ * our network callback list.
+ *
+ * @param ifname Name of the corresponding interface.
+ * @param network_id ID of the corresponding network.
+ * @param callback Binder reference of the |INetworkCallback| object.
+ */
+void BinderManager::removeNetworkCallbackBinderObject(
+ const std::string &ifname, int network_id,
+ const android::sp<fi::w1::wpa_supplicant::INetworkCallback> &callback)
+{
+ if (ifname.empty() || network_id < 0)
+ return;
+
+ // Generate the key to be used to lookup the network.
+ const std::string network_key =
+ getNetworkObjectMapKey(ifname, network_id);
+
+ auto network_callback_map_iter =
+ network_callbacks_map_.find(network_key);
+ if (network_callback_map_iter == network_callbacks_map_.end())
+ return;
+
+ auto &network_callback_list = network_callback_map_iter->second;
+ network_callback_list.erase(
+ std::remove(
+ network_callback_list.begin(), network_callback_list.end(),
+ callback),
+ network_callback_list.end());
+}
+
+/**
+ * Add callback to the corresponding list after linking to death on the
+ * corresponding binder object reference.
+ *
+ * @param callback Binder reference of the |INetworkCallback| object.
+ *
+ * @return 0 on success, 1 on failure.
+ */
+template <class CallbackType>
+int BinderManager::registerForDeathAndAddCallbackBinderObjectToList(
+ const android::sp<CallbackType> &callback,
+ const std::function<void(const android::sp<CallbackType> &)>
+ &on_binder_died_fctor,
+ std::vector<android::sp<CallbackType>> &callback_list)
+{
+ auto death_notifier = new CallbackObjectDeathNotifier<CallbackType>(
+ callback, on_binder_died_fctor);
+ // Use the |callback.get()| as cookie so that we don't need to
+ // store a reference to this |CallbackObjectDeathNotifier| instance
+ // to use in |unlinkToDeath| later.
+ // NOTE: This may cause an immediate callback if the object is already dead,
+ // so add it to the list before we register for callback!
+ callback_list.push_back(callback);
+ if (android::IInterface::asBinder(callback)->linkToDeath(
+ death_notifier, callback.get()) != android::OK) {
+ wpa_printf(
+ MSG_ERROR, "Error registering for death notification for "
+ "supplicant callback object");
+ callback_list.erase(
+ std::remove(
+ callback_list.begin(), callback_list.end(), callback),
+ callback_list.end());
+ return 1;
+ }
+ return 0;
+}
} // namespace wpa_supplicant_binder
diff --git a/wpa_supplicant/binder/binder_manager.h b/wpa_supplicant/binder/binder_manager.h
index 99fa510..1d9485b 100644
--- a/wpa_supplicant/binder/binder_manager.h
+++ b/wpa_supplicant/binder/binder_manager.h
@@ -75,6 +75,24 @@
const std::string
getNetworkObjectMapKey(const std::string &ifname, int network_id);
+ void removeSupplicantCallbackBinderObject(
+ const android::sp<fi::w1::wpa_supplicant::ISupplicantCallback>
+ &callback);
+ void removeIfaceCallbackBinderObject(
+ const std::string &ifname,
+ const android::sp<fi::w1::wpa_supplicant::IIfaceCallback>
+ &callback);
+ void removeNetworkCallbackBinderObject(
+ const std::string &ifname, int network_id,
+ const android::sp<fi::w1::wpa_supplicant::INetworkCallback>
+ &callback);
+ template <class CallbackType>
+ int registerForDeathAndAddCallbackBinderObjectToList(
+ const android::sp<CallbackType> &callback,
+ const std::function<void(const android::sp<CallbackType> &)>
+ &on_binder_died_fctor,
+ std::vector<android::sp<CallbackType>> &callback_list);
+
// Singleton instance of this class.
static BinderManager *instance_;
// The main binder service object.
@@ -87,6 +105,57 @@
// wpa_supplicant. This map is keyed in by the corresponding
// |ifname| & |network_id|.
std::map<const std::string, android::sp<Network>> network_object_map_;
+
+ // Callback registered for the main binder service object.
+ std::vector<android::sp<fi::w1::wpa_supplicant::ISupplicantCallback>>
+ supplicant_callbacks_;
+ // Map of all the callbacks registered for interface specific
+ // binder objects controlled by wpa_supplicant. This map is keyed in by
+ // the corresponding |ifname|.
+ std::map<
+ const std::string,
+ std::vector<android::sp<fi::w1::wpa_supplicant::IIfaceCallback>>>
+ iface_callbacks_map_;
+ // Map of all the callbacks registered for network specific
+ // binder objects controlled by wpa_supplicant. This map is keyed in by
+ // the corresponding |ifname| & |network_id|.
+ std::map<
+ const std::string,
+ std::vector<android::sp<fi::w1::wpa_supplicant::INetworkCallback>>>
+ network_callbacks_map_;
+
+ /**
+ * Helper class used to deregister the callback object reference from
+ * our
+ * callback list on the death of the binder object.
+ * This class stores a reference of the callback binder object and a
+ * function to be called to indicate the death of the binder object.
+ */
+ template <class CallbackType>
+ class CallbackObjectDeathNotifier
+ : public android::IBinder::DeathRecipient
+ {
+ public:
+ CallbackObjectDeathNotifier(
+ const android::sp<CallbackType> &callback,
+ const std::function<void(const android::sp<CallbackType> &)>
+ &on_binder_died)
+ : callback_(callback), on_binder_died_(on_binder_died)
+ {
+ }
+ void binderDied(
+ const android::wp<android::IBinder> & /* who */) override
+ {
+ on_binder_died_(callback_);
+ }
+
+ private:
+ // The callback binder object reference.
+ const android::sp<CallbackType> callback_;
+ // Callback function to be called when the binder dies.
+ const std::function<void(const android::sp<CallbackType> &)>
+ on_binder_died_;
+ };
};
} // namespace wpa_supplicant_binder