Add initial implementation for the mainline
supplicant service.

This provides the initialization and teardown
logic, as well as an implementation of the
current AIDL interface.

Bug: 365585450
Test: Manual test - Retrieve service in the
      framework and call the terminate method.
Change-Id: I30e5e4dbaf9cd5c13955045d3dc73fad4f0e3c1b
diff --git a/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp b/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp
new file mode 100644
index 0000000..97ad056
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/mainline_supplicant.cpp
@@ -0,0 +1,21 @@
+/*
+ * WPA Supplicant - Mainline supplicant AIDL implementation
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "mainline_supplicant.h"
+
+using ::ndk::ScopedAStatus;
+
+MainlineSupplicant::MainlineSupplicant(struct wpa_global* global) {
+    wpa_global_ = global;
+}
+
+ndk::ScopedAStatus MainlineSupplicant::terminate() {
+    wpa_printf(MSG_INFO, "Terminating...");
+    wpa_supplicant_terminate_proc(wpa_global_);
+    return ndk::ScopedAStatus::ok();
+}
diff --git a/wpa_supplicant/aidl/mainline/mainline_supplicant.h b/wpa_supplicant/aidl/mainline/mainline_supplicant.h
new file mode 100644
index 0000000..4cdc9c8
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/mainline_supplicant.h
@@ -0,0 +1,34 @@
+/*
+ * WPA Supplicant - Mainline supplicant AIDL implementation
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MAINLINE_SUPPLICANT_IMPL_H
+#define MAINLINE_SUPPLICANT_IMPL_H
+
+#include <aidl/android/system/wifi/mainline_supplicant/BnMainlineSupplicant.h>
+
+extern "C"
+{
+#include "utils/common.h"
+#include "utils/includes.h"
+#include "utils/wpa_debug.h"
+#include "wpa_supplicant_i.h"
+}
+
+using ::aidl::android::system::wifi::mainline_supplicant::BnMainlineSupplicant;
+
+class MainlineSupplicant : public BnMainlineSupplicant {
+    public:
+        MainlineSupplicant(struct wpa_global* global);
+        ndk::ScopedAStatus terminate();
+
+    private:
+        // Raw pointer to the global structure maintained by the core
+        struct wpa_global* wpa_global_;
+};
+
+#endif  // MAINLINE_SUPPLICANT_IMPL_H
diff --git a/wpa_supplicant/aidl/mainline/service.cpp b/wpa_supplicant/aidl/mainline/service.cpp
new file mode 100644
index 0000000..da343ea
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/service.cpp
@@ -0,0 +1,91 @@
+/*
+ * WPA Supplicant - Mainline supplicant service
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "mainline_supplicant.h"
+
+extern "C"
+{
+#include "aidl_i.h"
+#include "service.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/includes.h"
+#include "utils/wpa_debug.h"
+}
+
+using ::ndk::SharedRefBase;
+
+/* Handler for requests to the service */
+void aidl_sock_handler(int /* sock */, void * /* eloop_ctx */, void * /* sock_ctx */) {
+    // Suppress warning, since this service is only available after Android V
+    if (__builtin_available(android __ANDROID_API_V__, *)) {
+        ABinderProcess_handlePolledCommands();
+    }
+}
+
+bool register_service(struct wpa_global *global) {
+    wpa_printf(MSG_INFO, "Registering as a lazy service");
+    std::string service_name = "wifi_mainline_supplicant";
+    std::shared_ptr<MainlineSupplicant> service = SharedRefBase::make<MainlineSupplicant>(global);
+
+    // Suppress warning, since this service is only available after Android V
+    if (__builtin_available(android __ANDROID_API_V__, *)) {
+        int status =
+            AServiceManager_registerLazyService(service->asBinder().get(), service_name.c_str());
+        if (status != EX_NONE) {
+            wpa_printf(MSG_ERROR, "Registration failed with status %d", status);
+        }
+        return status == EX_NONE;
+    }
+    return false;
+}
+
+struct wpas_aidl_priv *mainline_aidl_init(struct wpa_global *global) {
+    wpa_printf(MSG_INFO, "Initializing the mainline supplicant service");
+    struct wpas_aidl_priv *priv = (wpas_aidl_priv *)os_zalloc(sizeof(*priv));
+    if (!priv) {
+        wpa_printf(MSG_ERROR, "Unable to allocate the global AIDL object");
+        return NULL;
+    }
+    priv->global = global;
+
+    // Suppress warning, since this service is only available after Android V
+    if (__builtin_available(android __ANDROID_API_V__, *)) {
+        ABinderProcess_setupPolling(&priv->aidl_fd);
+    }
+    if (priv->aidl_fd < 0) {
+        wpa_printf(MSG_ERROR, "Unable to set up polling");
+        mainline_aidl_deinit(priv);
+        return NULL;
+    }
+
+    if (eloop_register_read_sock(priv->aidl_fd, aidl_sock_handler, global, priv) < 0) {
+        wpa_printf(MSG_ERROR, "Unable to register eloop read socket");
+        mainline_aidl_deinit(priv);
+        return NULL;
+    }
+
+    if (!register_service(global)) {
+        wpa_printf(MSG_ERROR, "Unable to register service");
+        mainline_aidl_deinit(priv);
+        return NULL;
+    }
+
+    wpa_printf(MSG_INFO, "AIDL setup is complete");
+    return priv;
+}
+
+void mainline_aidl_deinit(struct wpas_aidl_priv *priv) {
+    if (!priv) return;
+    wpa_printf(MSG_INFO, "Deiniting the mainline supplicant service");
+    eloop_unregister_read_sock(priv->aidl_fd);
+    os_free(priv);
+}
diff --git a/wpa_supplicant/aidl/mainline/service.h b/wpa_supplicant/aidl/mainline/service.h
new file mode 100644
index 0000000..6d213e7
--- /dev/null
+++ b/wpa_supplicant/aidl/mainline/service.h
@@ -0,0 +1,27 @@
+/*
+ * WPA Supplicant - Mainline supplicant service
+ * Copyright (c) 2024, Google Inc. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MAINLINE_SUPPLICANT_SERVICE_H
+#define MAINLINE_SUPPLICANT_SERVICE_H
+
+#ifdef _cplusplus
+extern "C"
+{
+#endif  // _cplusplus
+
+struct wpas_aidl_priv;
+struct wpa_global;
+
+struct wpas_aidl_priv *mainline_aidl_init(struct wpa_global *global);
+void mainline_aidl_deinit(struct wpas_aidl_priv *priv);
+
+#ifdef _cplusplus
+}
+#endif  // _cplusplus
+
+#endif  // MAINLINE_SUPPLICANT_SERVICE_H
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index c1258a8..1fb2628 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -28,6 +28,10 @@
 #include "notify.h"
 #include "aidl/vendor/aidl.h"
 
+#ifdef MAINLINE_SUPPLICANT
+#include "aidl/mainline/service.h"
+#endif
+
 int wpas_notify_supplicant_initialized(struct wpa_global *global)
 {
 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
@@ -48,6 +52,12 @@
 	}
 #endif /* CONFIG_AIDL */
 
+#ifdef MAINLINE_SUPPLICANT
+	global->aidl = mainline_aidl_init(global);
+	if (!global->aidl)
+		return -1;
+#endif /* MAINLINE_SUPPLICANT */
+
 	return 0;
 }
 
@@ -63,6 +73,12 @@
 	if (global->aidl)
 		wpas_aidl_deinit(global->aidl);
 #endif /* CONFIG_AIDL */
+
+#ifdef MAINLINE_SUPPLICANT
+	if (global->aidl)
+		mainline_aidl_deinit(global->aidl);
+#endif /* MAINLINE_SUPPLICANT */
+
 }