hostapd(hidl): Add asynchronous failure callback

Changes in the CL:
a) Add a new callback registration mechanism for the hostapd HIDL interface.
b) Use the existing |setup_complete_cb| callback provided by the hostapd
core to trigger the new onFailure() HIDL callback.

Bug: 112705137
Test: Manual test. Simulated the issue reported in the bug and ensured
that UI toggled off.
Change-Id: I7211e313c107be3a4a7a52af69ffe1e565b5147b
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index ce4fc84..93c8d80 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -1136,6 +1136,7 @@
 endif
 ifeq ($(HOSTAPD_USE_HIDL), y)
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.0
+LOCAL_SHARED_LIBRARIES += android.hardware.wifi.hostapd@1.1
 LOCAL_SHARED_LIBRARIES += libbase libhidlbase libhidltransport libhwbinder libutils
 LOCAL_STATIC_LIBRARIES += libhostapd_hidl
 endif
@@ -1178,12 +1179,13 @@
 LOCAL_CPPFLAGS := $(L_CPPFLAGS)
 LOCAL_CFLAGS := $(L_CFLAGS)
 LOCAL_C_INCLUDES := $(INCLUDES)
-HIDL_INTERFACE_VERSION = 1.0
+HIDL_INTERFACE_VERSION = 1.1
 LOCAL_SRC_FILES := \
     hidl/$(HIDL_INTERFACE_VERSION)/hidl.cpp \
     hidl/$(HIDL_INTERFACE_VERSION)/hostapd.cpp
 LOCAL_SHARED_LIBRARIES := \
     android.hardware.wifi.hostapd@1.0 \
+    android.hardware.wifi.hostapd@1.1 \
     libbase \
     libhidlbase \
     libhidltransport \
diff --git a/hostapd/hidl/1.0/hidl.cpp b/hostapd/hidl/1.1/hidl.cpp
similarity index 93%
rename from hostapd/hidl/1.0/hidl.cpp
rename to hostapd/hidl/1.1/hidl.cpp
index a0dc50e..2051e7b 100644
--- a/hostapd/hidl/1.0/hidl.cpp
+++ b/hostapd/hidl/1.1/hidl.cpp
@@ -22,8 +22,8 @@
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::IPCThreadState;
-using android::hardware::wifi::hostapd::V1_0::IHostapd;
-using android::hardware::wifi::hostapd::V1_0::implementation::Hostapd;
+using android::hardware::wifi::hostapd::V1_1::IHostapd;
+using android::hardware::wifi::hostapd::V1_1::implementation::Hostapd;
 
 // This file is a bridge between the hostapd code written in 'C' and the HIDL
 // interface in C++. So, using "C" style static globals here!
diff --git a/hostapd/hidl/1.0/hidl.h b/hostapd/hidl/1.1/hidl.h
similarity index 100%
rename from hostapd/hidl/1.0/hidl.h
rename to hostapd/hidl/1.1/hidl.h
diff --git a/hostapd/hidl/1.0/hidl_return_util.h b/hostapd/hidl/1.1/hidl_return_util.h
similarity index 96%
rename from hostapd/hidl/1.0/hidl_return_util.h
rename to hostapd/hidl/1.1/hidl_return_util.h
index 1625dc2..d914ee2 100644
--- a/hostapd/hidl/1.0/hidl_return_util.h
+++ b/hostapd/hidl/1.1/hidl_return_util.h
@@ -16,7 +16,7 @@
 namespace hardware {
 namespace wifi {
 namespace hostapd {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 namespace hidl_return_util {
 
@@ -36,7 +36,7 @@
 
 }  // namespace hidl_return_util
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace hostapd
 }  // namespace wifi
 }  // namespace hardware
diff --git a/hostapd/hidl/1.0/hostapd.cpp b/hostapd/hidl/1.1/hostapd.cpp
similarity index 81%
rename from hostapd/hidl/1.0/hostapd.cpp
rename to hostapd/hidl/1.1/hostapd.cpp
index 3cd78b3..340b22c 100644
--- a/hostapd/hidl/1.0/hostapd.cpp
+++ b/hostapd/hidl/1.1/hostapd.cpp
@@ -33,7 +33,7 @@
 using android::base::RemoveFileIfExists;
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
-using android::hardware::wifi::hostapd::V1_0::IHostapd;
+using android::hardware::wifi::hostapd::V1_1::IHostapd;
 
 std::string WriteHostapdConfig(
     const std::string& interface_name, const std::string& config)
@@ -187,15 +187,35 @@
 	    hw_mode_as_string.c_str(), ht_cap_vht_oper_chwidth_as_string.c_str(),
 	    nw_params.isHidden ? 1 : 0, encryption_config_as_string.c_str());
 }
+
+// hostapd core functions accept "C" style function pointers, so use global
+// functions to pass to the hostapd core function and store the corresponding
+// std::function methods to be invoked.
+//
+// NOTE: Using the pattern from the vendor HAL (wifi_legacy_hal.cpp).
+//
+// Callback to be invoked once setup is complete
+std::function<void(struct hostapd_data*)> on_setup_complete_internal_callback;
+void onAsyncSetupCompleteCb(void* ctx)
+{
+	struct hostapd_data* iface_hapd = (struct hostapd_data*)ctx;
+	if (on_setup_complete_internal_callback) {
+		on_setup_complete_internal_callback(iface_hapd);
+		// Invalidate this callback since we don't want this firing
+		// again.
+		on_setup_complete_internal_callback = nullptr;
+	}
+}
 }  // namespace
 
 namespace android {
 namespace hardware {
 namespace wifi {
 namespace hostapd {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
 using hidl_return_util::call;
+using namespace android::hardware::wifi::hostapd::V1_0;
 
 Hostapd::Hostapd(struct hapd_interfaces* interfaces) : interfaces_(interfaces)
 {}
@@ -216,12 +236,20 @@
 	    this, &Hostapd::removeAccessPointInternal, _hidl_cb, iface_name);
 }
 
-Return<void> Hostapd::terminate() {
+Return<void> Hostapd::terminate()
+{
 	wpa_printf(MSG_INFO, "Terminating...");
 	eloop_terminate();
 	return Void();
 }
 
+Return<void> Hostapd::registerCallback(
+    const sp<IHostapdCallback>& callback, registerCallback_cb _hidl_cb)
+{
+	return call(
+	    this, &Hostapd::registerCallbackInternal, _hidl_cb, callback);
+}
+
 HostapdStatus Hostapd::addAccessPointInternal(
     const IfaceParams& iface_params, const NetworkParams& nw_params)
 {
@@ -256,6 +284,23 @@
 	struct hostapd_data* iface_hapd =
 	    hostapd_get_iface(interfaces_, iface_params.ifaceName.c_str());
 	WPA_ASSERT(iface_hapd != nullptr && iface_hapd->iface != nullptr);
+	// Register the setup complete callbacks
+	on_setup_complete_internal_callback =
+	    [this](struct hostapd_data* iface_hapd) {
+		    wpa_printf(
+			MSG_DEBUG, "AP interface setup completed - state %s",
+			hostapd_state_text(iface_hapd->iface->state));
+		    if (iface_hapd->iface->state == HAPD_IFACE_DISABLED) {
+			    // Invoke the failure callback on all registered
+			    // clients.
+			    for (const auto& callback : callbacks_) {
+				    callback->onFailure(
+					iface_hapd->conf->iface);
+			    }
+		    }
+	    };
+	iface_hapd->setup_complete_cb = onAsyncSetupCompleteCb;
+	iface_hapd->setup_complete_cb_ctx = iface_hapd;
 	if (hostapd_enable_iface(iface_hapd->iface) < 0) {
 		wpa_printf(
 		    MSG_ERROR, "Enabling interface %s failed",
@@ -278,8 +323,16 @@
 	}
 	return {HostapdStatusCode::SUCCESS, ""};
 }
+
+HostapdStatus Hostapd::registerCallbackInternal(
+    const sp<IHostapdCallback>& callback)
+{
+	callbacks_.push_back(callback);
+	return {HostapdStatusCode::SUCCESS, ""};
+}
+
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace hostapd
 }  // namespace wifi
 }  // namespace hardware
diff --git a/hostapd/hidl/1.0/hostapd.h b/hostapd/hidl/1.1/hostapd.h
similarity index 76%
rename from hostapd/hidl/1.0/hostapd.h
rename to hostapd/hidl/1.1/hostapd.h
index 7985fd9..3438d8b 100644
--- a/hostapd/hidl/1.0/hostapd.h
+++ b/hostapd/hidl/1.1/hostapd.h
@@ -14,7 +14,8 @@
 
 #include <android-base/macros.h>
 
-#include <android/hardware/wifi/hostapd/1.0/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.1/IHostapd.h>
+#include <android/hardware/wifi/hostapd/1.1/IHostapdCallback.h>
 
 extern "C"
 {
@@ -28,15 +29,16 @@
 namespace hardware {
 namespace wifi {
 namespace hostapd {
-namespace V1_0 {
+namespace V1_1 {
 namespace implementation {
+using namespace android::hardware::wifi::hostapd::V1_0;
 
 /**
  * Implementation of the hostapd hidl object. This hidl
  * object is used core for global control operations on
  * hostapd.
  */
-class Hostapd : public V1_0::IHostapd
+class Hostapd : public V1_1::IHostapd
 {
 public:
 	Hostapd(hapd_interfaces* interfaces);
@@ -50,20 +52,27 @@
 	    const hidl_string& iface_name,
 	    removeAccessPoint_cb _hidl_cb) override;
 	Return<void> terminate() override;
+	Return<void> registerCallback(
+	    const sp<IHostapdCallback>& callback,
+	    registerCallback_cb _hidl_cb) override;
 
 private:
 	// Corresponding worker functions for the HIDL methods.
 	HostapdStatus addAccessPointInternal(
 	    const IfaceParams& iface_params, const NetworkParams& nw_params);
 	HostapdStatus removeAccessPointInternal(const std::string& iface_name);
+	HostapdStatus registerCallbackInternal(
+	    const sp<IHostapdCallback>& callback);
 
 	// Raw pointer to the global structure maintained by the core.
 	struct hapd_interfaces* interfaces_;
+	// Callbacks registered.
+	std::vector<sp<IHostapdCallback>> callbacks_;
 
 	DISALLOW_COPY_AND_ASSIGN(Hostapd);
 };
 }  // namespace implementation
-}  // namespace V1_0
+}  // namespace V1_1
 }  // namespace hostapd
 }  // namespace wifi
 }  // namespace hardware
diff --git a/hostapd/hostapd.android.rc b/hostapd/hostapd.android.rc
index 37a95c2..c8792d6 100644
--- a/hostapd/hostapd.android.rc
+++ b/hostapd/hostapd.android.rc
@@ -13,6 +13,7 @@
 
 service hostapd /vendor/bin/hw/hostapd
     interface android.hardware.wifi.hostapd@1.0::IHostapd default
+    interface android.hardware.wifi.hostapd@1.1::IHostapd default
     class main
     capabilities NET_ADMIN NET_RAW
     user wifi