Ensure config file for wpa_supplicant exists

Add ensuring the configuration file for wpa_supplicant hidl 1.0.
When initializing hidl service, supplicant will copy the
template configuration file if the configuration file is not exist.

Bug: 74504608
Test: Wi-Fi is successfully turned on.
Change-Id: I1c62ecf898445d2ddfb1efd26b2b0862e5ff87ff
Merged-In: I1c62ecf898445d2ddfb1efd26b2b0862e5ff87ff
(cherry picked from commit f5ff1e139e718d9c76edc2d8a11807936778ad97)
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 2d87f75..df27835 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -1723,7 +1723,7 @@
 endif
 ifeq ($(WPA_SUPPLICANT_USE_HIDL), y)
 LOCAL_SHARED_LIBRARIES += android.hardware.wifi.supplicant@1.0
-LOCAL_SHARED_LIBRARIES += libhidlbase libhidltransport libhwbinder libutils
+LOCAL_SHARED_LIBRARIES += libhidlbase libhidltransport libhwbinder libutils libbase
 LOCAL_STATIC_LIBRARIES += libwpa_hidl
 endif
 include $(BUILD_EXECUTABLE)
@@ -1785,6 +1785,7 @@
     hidl/$(HIDL_INTERFACE_VERSION)/supplicant.cpp
 LOCAL_SHARED_LIBRARIES := \
     android.hardware.wifi.supplicant@$(HIDL_INTERFACE_VERSION) \
+    libbase \
     libhidlbase \
     libhidltransport \
     libhwbinder \
diff --git a/wpa_supplicant/hidl/1.0/hidl_manager.cpp b/wpa_supplicant/hidl/1.0/hidl_manager.cpp
index 152203c..4655da2 100644
--- a/wpa_supplicant/hidl/1.0/hidl_manager.cpp
+++ b/wpa_supplicant/hidl/1.0/hidl_manager.cpp
@@ -395,6 +395,10 @@
 	if (supplicant_object_->registerAsService() != android::NO_ERROR) {
 		return 1;
 	}
+	if (!supplicant_object_->ensureConfigFileExists()) {
+		// If config file does not exist, we cannot start supplicant.
+		return 1;
+	}
 	return 0;
 }
 
diff --git a/wpa_supplicant/hidl/1.0/supplicant.cpp b/wpa_supplicant/hidl/1.0/supplicant.cpp
index a381511..bf009b5 100644
--- a/wpa_supplicant/hidl/1.0/supplicant.cpp
+++ b/wpa_supplicant/hidl/1.0/supplicant.cpp
@@ -11,6 +11,110 @@
 #include "hidl_return_util.h"
 #include "supplicant.h"
 
+#include <android-base/file.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+namespace {
+constexpr char kStaIfaceConfPath[] =
+    "/data/misc/wifi/wpa_supplicant.conf";
+constexpr char kP2pIfaceConfPath[] =
+    "/data/misc/wifi/p2p_supplicant.conf";
+// Migrate conf files for existing devices.
+constexpr char kTemplateConfPath[] =
+    "/vendor/etc/wifi/wpa_supplicant.conf";
+constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
+
+int copyFile(
+    const std::string& src_file_path, const std::string& dest_file_path)
+{
+	std::string file_contents;
+	if (!android::base::ReadFileToString(src_file_path, &file_contents)) {
+		wpa_printf(
+		    MSG_ERROR, "Failed to read from %s. Errno: %s",
+		    src_file_path.c_str(), strerror(errno));
+		return -1;
+	}
+	if (!android::base::WriteStringToFile(
+		file_contents, dest_file_path, kConfigFileMode, getuid(),
+		getgid())) {
+		wpa_printf(
+		    MSG_ERROR, "Failed to write to %s. Errno: %s",
+		    dest_file_path.c_str(), strerror(errno));
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Copy |src_file_path| to |dest_file_path| if it exists.
+ *
+ * Returns 1 if |src_file_path| does not exists,
+ * Returns -1 if the copy fails.
+ * Returns 0 if the copy succeeds.
+ */
+int copyFileIfItExists(
+    const std::string& src_file_path, const std::string& dest_file_path)
+{
+	int ret = access(src_file_path.c_str(), R_OK);
+	if ((ret != 0) && (errno == ENOENT)) {
+		return 1;
+	}
+	ret = copyFile(src_file_path, dest_file_path);
+	if (ret != 0) {
+		wpa_printf(
+		    MSG_ERROR, "Failed copying %s to %s.",
+		    src_file_path.c_str(), dest_file_path.c_str());
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Ensure that the specified config file pointed by |config_file_path| exists.
+ * a) If the |config_file_path| exists with the correct permissions, return.
+ * b) If the |config_file_path| does not exists, copy over the contents of
+ * |template_config_file_path|.
+ */
+int copyTemplateConfigFileIfNotExists(
+    const std::string& config_file_path,
+    const std::string& template_config_file_path)
+{
+	int ret = access(config_file_path.c_str(), R_OK | W_OK);
+	if (ret == 0) {
+		return 0;
+	}
+	if (errno == EACCES) {
+		ret = chmod(config_file_path.c_str(), kConfigFileMode);
+		if (ret == 0) {
+			return 0;
+		} else {
+			wpa_printf(
+			    MSG_ERROR, "Cannot set RW to %s. Errno: %s",
+			    config_file_path.c_str(), strerror(errno));
+			return -1;
+		}
+	} else if (errno != ENOENT) {
+		wpa_printf(
+		    MSG_ERROR, "Cannot acces %s. Errno: %s",
+		    config_file_path.c_str(), strerror(errno));
+		return -1;
+	}
+	ret = copyFileIfItExists(template_config_file_path, config_file_path);
+	if (ret == 0) {
+		wpa_printf(
+		    MSG_INFO, "Copied template conf file from %s to %s",
+		    template_config_file_path.c_str(), config_file_path.c_str());
+		return 0;
+	} else if (ret == -1) {
+		unlink(config_file_path.c_str());
+		return -1;
+	}
+	// Did not create the conf file.
+	return -1;
+}
+}  // namespace
+
 namespace android {
 namespace hardware {
 namespace wifi {
@@ -31,6 +135,24 @@
 	return true;
 }
 
+bool Supplicant::ensureConfigFileExists()
+{
+	// To support Android P Wifi framework, make sure the config file exists.
+	if (copyTemplateConfigFileIfNotExists(
+		kStaIfaceConfPath, kTemplateConfPath) != 0) {
+		wpa_printf(MSG_ERROR, "Conf file does not exists: %s",
+		    kStaIfaceConfPath);
+		return false;
+	}
+	// P2P configuration file is not madatory but required for some devices.
+	if (copyTemplateConfigFileIfNotExists(
+		kP2pIfaceConfPath, kTemplateConfPath) != 0) {
+		wpa_printf(MSG_INFO, "Conf file does not exists: %s",
+		    kP2pIfaceConfPath);
+	}
+	return true;
+}
+
 Return<void> Supplicant::getInterface(
     const IfaceInfo& iface_info, getInterface_cb _hidl_cb)
 {
diff --git a/wpa_supplicant/hidl/1.0/supplicant.h b/wpa_supplicant/hidl/1.0/supplicant.h
index 1ad8402..04d1ae1 100644
--- a/wpa_supplicant/hidl/1.0/supplicant.h
+++ b/wpa_supplicant/hidl/1.0/supplicant.h
@@ -40,6 +40,7 @@
 	Supplicant(struct wpa_global* global);
 	~Supplicant() override = default;
 	bool isValid();
+	bool ensureConfigFileExists();
 
 	// Hidl methods exposed.
 	Return<void> getInterface(