diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2016-08-25 19:43:19 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2016-08-25 19:43:20 +0000 |
commit | 5d0e81f974deddce0d6fedceb57bff1f2c83a64e (patch) | |
tree | bbb4b8c59367bc8b21b34bd2dc56ef3386e0f28a /libwifi_system | |
parent | c13a0778c3d9e081bb328bcea0bc64914de9b02e (diff) | |
parent | 8c784cd2472164c2bcbe33375c173f67247955eb (diff) | |
download | android_frameworks_opt_net_wifi-5d0e81f974deddce0d6fedceb57bff1f2c83a64e.tar.gz android_frameworks_opt_net_wifi-5d0e81f974deddce0d6fedceb57bff1f2c83a64e.tar.bz2 android_frameworks_opt_net_wifi-5d0e81f974deddce0d6fedceb57bff1f2c83a64e.zip |
Merge "Move supplicant management functions to delegate"
Diffstat (limited to 'libwifi_system')
-rw-r--r-- | libwifi_system/Android.mk | 1 | ||||
-rw-r--r-- | libwifi_system/include/wifi_system/supplicant_manager.h | 48 | ||||
-rw-r--r-- | libwifi_system/include/wifi_system/wifi.h | 14 | ||||
-rw-r--r-- | libwifi_system/supplicant_manager.cpp | 221 | ||||
-rw-r--r-- | libwifi_system/testlib/include/wifi_system_test/mock_supplicant_manager.h | 38 | ||||
-rw-r--r-- | libwifi_system/wifi.cpp | 187 |
6 files changed, 319 insertions, 190 deletions
diff --git a/libwifi_system/Android.mk b/libwifi_system/Android.mk index 61d340a23..f969247e1 100644 --- a/libwifi_system/Android.mk +++ b/libwifi_system/Android.mk @@ -54,6 +54,7 @@ LOCAL_SRC_FILES := \ hostapd_manager.cpp \ interface_tool.cpp \ hal_tool.cpp \ + supplicant_manager.cpp \ wifi.cpp include $(BUILD_SHARED_LIBRARY) diff --git a/libwifi_system/include/wifi_system/supplicant_manager.h b/libwifi_system/include/wifi_system/supplicant_manager.h new file mode 100644 index 000000000..c666fc95a --- /dev/null +++ b/libwifi_system/include/wifi_system/supplicant_manager.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_WIFI_SYSTEM_SUPPLICANT_MANAGER_H +#define ANDROID_WIFI_SYSTEM_SUPPLICANT_MANAGER_H + +#include <android-base/macros.h> + +namespace android { +namespace wifi_system { + +class SupplicantManager { + public: + SupplicantManager() = default; + virtual ~SupplicantManager() = default; + + // Request that supplicant be started. + // Returns true on success. + virtual bool StartSupplicant(); + + // Request that a running instance of supplicant be stopped. + // Returns true on success. + virtual bool StopSupplicant(); + + // Returns true iff supplicant is still running. + virtual bool IsSupplicantRunning(); + + private: + DISALLOW_COPY_AND_ASSIGN(SupplicantManager); +}; // class SupplicantManager + +} // namespace wifi_system +} // namespace android + +#endif // ANDROID_WIFI_SYSTEM_SUPPLICANT_MANAGER_H diff --git a/libwifi_system/include/wifi_system/wifi.h b/libwifi_system/include/wifi_system/wifi.h index 0cfbf3ee8..6d017ecc5 100644 --- a/libwifi_system/include/wifi_system/wifi.h +++ b/libwifi_system/include/wifi_system/wifi.h @@ -25,20 +25,6 @@ namespace wifi_system { extern const char kWiFiEntropyFile[]; /** - * Start supplicant. - * - * @return 0 on success, < 0 on failure. - */ -int wifi_start_supplicant(); - -/** - * Stop supplicant. - * - * @return 0 on success, < 0 on failure. - */ -int wifi_stop_supplicant(); - -/** * Open a connection to supplicant * * @return 0 on success, < 0 on failure. diff --git a/libwifi_system/supplicant_manager.cpp b/libwifi_system/supplicant_manager.cpp new file mode 100644 index 000000000..833739a05 --- /dev/null +++ b/libwifi_system/supplicant_manager.cpp @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wifi_system/supplicant_manager.h" + +#include <android-base/logging.h> +#include <cutils/properties.h> +#include <fcntl.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +// This ugliness is necessary to access internal implementation details +// of the property subsystem. +#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ +#include <sys/_system_properties.h> + +// Certain system (emulators) don't have wpa_supplicant installed at all. +#ifdef LIBWPA_CLIENT_EXISTS +#include <libwpa_client/wpa_ctrl.h> +#else +void wpa_ctrl_cleanup(void) {} +#endif + +#include "wifi_system/wifi.h" + +namespace android { +namespace wifi_system { +namespace { + +const char kSupplicantInitProperty[] = "init.svc.wpa_supplicant"; +const char kSupplicantConfigTemplatePath[] = + "/system/etc/wifi/wpa_supplicant.conf"; +const char kSupplicantConfigFile[] = "/data/misc/wifi/wpa_supplicant.conf"; +const char kP2pConfigFile[] = "/data/misc/wifi/p2p_supplicant.conf"; +const char kSupplicantServiceName[] = "wpa_supplicant"; +constexpr mode_t kConfigFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + +int ensure_config_file_exists(const char* config_file) { + char buf[2048]; + int srcfd, destfd; + int nread; + int ret; + + ret = access(config_file, R_OK | W_OK); + if ((ret == 0) || (errno == EACCES)) { + if ((ret != 0) && (chmod(config_file, kConfigFileMode) != 0)) { + LOG(ERROR) << "Cannot set RW to \"" << config_file << "\": " + << strerror(errno); + return false; + } + return true; + } else if (errno != ENOENT) { + LOG(ERROR) << "Cannot access \"" << config_file << "\": " + << strerror(errno); + return false; + } + + srcfd = TEMP_FAILURE_RETRY(open(kSupplicantConfigTemplatePath, O_RDONLY)); + if (srcfd < 0) { + LOG(ERROR) << "Cannot open \"" << kSupplicantConfigTemplatePath << "\": " + << strerror(errno); + return false; + } + + destfd = TEMP_FAILURE_RETRY(open(config_file, + O_CREAT | O_RDWR, + kConfigFileMode)); + if (destfd < 0) { + close(srcfd); + LOG(ERROR) << "Cannot create \"" << config_file << "\": " + << strerror(errno); + return false; + } + + while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) { + if (nread < 0) { + LOG(ERROR) << "Error reading \"" << kSupplicantConfigTemplatePath + << "\": " << strerror(errno); + close(srcfd); + close(destfd); + unlink(config_file); + return false; + } + TEMP_FAILURE_RETRY(write(destfd, buf, nread)); + } + + close(destfd); + close(srcfd); + + /* chmod is needed because open() didn't set permisions properly */ + if (chmod(config_file, kConfigFileMode) < 0) { + LOG(ERROR) << "Error changing permissions of " << config_file + << " to 0660: " << strerror(errno); + unlink(config_file); + return false; + } + + return true; +} + +} // namespace + +bool SupplicantManager::StartSupplicant() { + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + int count = 200; /* wait at most 20 seconds for completion */ + const prop_info* pi; + unsigned serial = 0; + + /* Check whether already running */ + if (property_get(kSupplicantInitProperty, supp_status, NULL) && + strcmp(supp_status, "running") == 0) { + return true; + } + + /* Before starting the daemon, make sure its config file exists */ + if (ensure_config_file_exists(kSupplicantConfigFile) < 0) { + LOG(ERROR) << "Wi-Fi will not be enabled"; + return false; + } + + /* + * Some devices have another configuration file for the p2p interface. + * However, not all devices have this, and we'll let it slide if it + * is missing. For devices that do expect this file to exist, + * supplicant will refuse to start and emit a good error message. + * No need to check for it here. + */ + (void)ensure_config_file_exists(kP2pConfigFile); + + if (ensure_entropy_file_exists() < 0) { + LOG(ERROR) << "Wi-Fi entropy file was not created"; + } + + /* Clear out any stale socket files that might be left over. */ + wpa_ctrl_cleanup(); + + /* + * Get a reference to the status property, so we can distinguish + * the case where it goes stopped => running => stopped (i.e., + * it start up, but fails right away) from the case in which + * it starts in the stopped state and never manages to start + * running at all. + */ + pi = __system_property_find(kSupplicantInitProperty); + if (pi != NULL) { + serial = __system_property_serial(pi); + } + + property_set("ctl.start", kSupplicantServiceName); + sched_yield(); + + while (count-- > 0) { + if (pi == NULL) { + pi = __system_property_find(kSupplicantInitProperty); + } + if (pi != NULL) { + /* + * property serial updated means that init process is scheduled + * after we sched_yield, further property status checking is based on this + */ + if (__system_property_serial(pi) != serial) { + __system_property_read(pi, NULL, supp_status); + if (strcmp(supp_status, "running") == 0) { + return true; + } else if (strcmp(supp_status, "stopped") == 0) { + return false; + } + } + } + usleep(100000); + } + return false; +} + +bool SupplicantManager::StopSupplicant() { + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + int count = 50; /* wait at most 5 seconds for completion */ + + /* Check whether supplicant already stopped */ + if (property_get(kSupplicantInitProperty, supp_status, NULL) && + strcmp(supp_status, "stopped") == 0) { + return true; + } + + property_set("ctl.stop", kSupplicantServiceName); + sched_yield(); + + while (count-- > 0) { + if (property_get(kSupplicantInitProperty, supp_status, NULL)) { + if (strcmp(supp_status, "stopped") == 0) return true; + } + usleep(100000); + } + LOG(ERROR) << "Failed to stop supplicant"; + return false; +} + +bool SupplicantManager::IsSupplicantRunning() { + char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; + if (property_get(kSupplicantInitProperty, supp_status, NULL)) { + return strcmp(supp_status, "running") == 0; + } + return false; // Failed to read service status from init. +} + +} // namespace wifi_system +} // namespace android diff --git a/libwifi_system/testlib/include/wifi_system_test/mock_supplicant_manager.h b/libwifi_system/testlib/include/wifi_system_test/mock_supplicant_manager.h new file mode 100644 index 000000000..01d604f47 --- /dev/null +++ b/libwifi_system/testlib/include/wifi_system_test/mock_supplicant_manager.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_WIFI_SYSTEM_TEST_MOCK_SUPPLICANT_MANAGER_H +#define ANDROID_WIFI_SYSTEM_TEST_MOCK_SUPPLICANT_MANAGER_H + +#include <wifi_system/supplicant_manager.h> + +namespace android { +namespace wifi_system { + +class MockSupplicantManager : public SupplicantManager { + public: + ~MockSupplicantManager() override = default; + + MOCK_METHOD0(StartSupplicant, bool()); + MOCK_METHOD0(StopSupplicant, bool()); + MOCK_METHOD0(IsSupplicantRunning, bool()); + +}; // class MockSupplicantManager + +} // namespace wifi_system +} // namespace android + +#endif // ANDROID_WIFI_SYSTEM_TEST_MOCK_SUPPLICANT_MANAGER_H diff --git a/libwifi_system/wifi.cpp b/libwifi_system/wifi.cpp index 49aee188b..e76a938e9 100644 --- a/libwifi_system/wifi.cpp +++ b/libwifi_system/wifi.cpp @@ -36,6 +36,8 @@ #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ #include <sys/_system_properties.h> +#include "wifi_system/supplicant_manager.h" + #ifdef LIBWPA_CLIENT_EXISTS #include <libwpa_client/wpa_ctrl.h> #else @@ -77,11 +79,6 @@ static char primary_iface[PROPERTY_VALUE_MAX]; #define WIFI_DRIVER_LOADER_DELAY 1000000 const char IFACE_DIR[] = "/data/system/wpa_supplicant"; -const char SUPPLICANT_SERVICE_NAME[] = "wpa_supplicant"; -const char SUPPLICANT_INIT_PROPERTY[] = "init.svc.wpa_supplicant"; -const char SUPP_CONFIG_TEMPLATE[] = "/system/etc/wifi/wpa_supplicant.conf"; -const char SUPP_CONFIG_FILE[] = "/data/misc/wifi/wpa_supplicant.conf"; -const char P2P_CONFIG_FILE[] = "/data/misc/wifi/p2p_supplicant.conf"; const char IFNAME[] = "IFNAME="; #define IFNAMELEN (sizeof(IFNAME) - 1) @@ -113,170 +110,16 @@ void wifi_close_sockets() { } } -int ensure_config_file_exists(const char* config_file) { - char buf[2048]; - int srcfd, destfd; - int nread; - int ret; - - ret = access(config_file, R_OK | W_OK); - if ((ret == 0) || (errno == EACCES)) { - if ((ret != 0) && - (chmod(config_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) != 0)) { - ALOGE("Cannot set RW to \"%s\": %s", config_file, strerror(errno)); - return -1; - } - return 0; - } else if (errno != ENOENT) { - ALOGE("Cannot access \"%s\": %s", config_file, strerror(errno)); - return -1; - } - - srcfd = TEMP_FAILURE_RETRY(open(SUPP_CONFIG_TEMPLATE, O_RDONLY)); - if (srcfd < 0) { - ALOGE("Cannot open \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); - return -1; - } - - destfd = TEMP_FAILURE_RETRY(open(config_file, O_CREAT | O_RDWR, 0660)); - if (destfd < 0) { - close(srcfd); - ALOGE("Cannot create \"%s\": %s", config_file, strerror(errno)); - return -1; - } - - while ((nread = TEMP_FAILURE_RETRY(read(srcfd, buf, sizeof(buf)))) != 0) { - if (nread < 0) { - ALOGE("Error reading \"%s\": %s", SUPP_CONFIG_TEMPLATE, strerror(errno)); - close(srcfd); - close(destfd); - unlink(config_file); - return -1; - } - TEMP_FAILURE_RETRY(write(destfd, buf, nread)); - } - - close(destfd); - close(srcfd); - - /* chmod is needed because open() didn't set permisions properly */ - if (chmod(config_file, 0660) < 0) { - ALOGE("Error changing permissions of %s to 0660: %s", config_file, - strerror(errno)); - unlink(config_file); - return -1; - } - - return 0; -} - } // namespace const char kWiFiEntropyFile[] = "/data/misc/wifi/entropy.bin"; -int wifi_start_supplicant() { - char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; - int count = 200; /* wait at most 20 seconds for completion */ - const prop_info* pi; - unsigned serial = 0; - - /* Check whether already running */ - if (property_get(SUPPLICANT_INIT_PROPERTY, supp_status, NULL) && - strcmp(supp_status, "running") == 0) { - return 0; - } - - /* Before starting the daemon, make sure its config file exists */ - if (ensure_config_file_exists(SUPP_CONFIG_FILE) < 0) { - ALOGE("Wi-Fi will not be enabled"); - return -1; - } - - /* - * Some devices have another configuration file for the p2p interface. - * However, not all devices have this, and we'll let it slide if it - * is missing. For devices that do expect this file to exist, - * supplicant will refuse to start and emit a good error message. - * No need to check for it here. - */ - (void)ensure_config_file_exists(P2P_CONFIG_FILE); - - if (ensure_entropy_file_exists() < 0) { - ALOGE("Wi-Fi entropy file was not created"); - } - - /* Clear out any stale socket files that might be left over. */ - wpa_ctrl_cleanup(); - - /* - * Get a reference to the status property, so we can distinguish - * the case where it goes stopped => running => stopped (i.e., - * it start up, but fails right away) from the case in which - * it starts in the stopped state and never manages to start - * running at all. - */ - pi = __system_property_find(SUPPLICANT_INIT_PROPERTY); - if (pi != NULL) { - serial = __system_property_serial(pi); - } - - property_set("ctl.start", SUPPLICANT_SERVICE_NAME); - sched_yield(); - - while (count-- > 0) { - if (pi == NULL) { - pi = __system_property_find(SUPPLICANT_INIT_PROPERTY); - } - if (pi != NULL) { - /* - * property serial updated means that init process is scheduled - * after we sched_yield, further property status checking is based on this - */ - if (__system_property_serial(pi) != serial) { - __system_property_read(pi, NULL, supp_status); - if (strcmp(supp_status, "running") == 0) { - return 0; - } else if (strcmp(supp_status, "stopped") == 0) { - return -1; - } - } - } - usleep(100000); - } - return -1; -} - -int wifi_stop_supplicant() { - char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; - int count = 50; /* wait at most 5 seconds for completion */ - - /* Check whether supplicant already stopped */ - if (property_get(SUPPLICANT_INIT_PROPERTY, supp_status, NULL) && - strcmp(supp_status, "stopped") == 0) { - return 0; - } - - property_set("ctl.stop", SUPPLICANT_SERVICE_NAME); - sched_yield(); - - while (count-- > 0) { - if (property_get(SUPPLICANT_INIT_PROPERTY, supp_status, NULL)) { - if (strcmp(supp_status, "stopped") == 0) return 0; - } - usleep(100000); - } - ALOGE("Failed to stop supplicant"); - return -1; -} - namespace { int wifi_connect_on_socket_path(const char* path) { - char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; - /* Make sure supplicant is running */ - if (!property_get(SUPPLICANT_INIT_PROPERTY, supp_status, NULL) || - strcmp(supp_status, "running") != 0) { + android::wifi_system::SupplicantManager manager; + if (!manager.IsSupplicantRunning()) { ALOGE("Supplicant not running, cannot connect"); return -1; } @@ -331,20 +174,11 @@ int wifi_send_command(const char* cmd, char* reply, size_t* reply_len) { return 0; } -int wifi_supplicant_connection_active() { - char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; - - if (property_get(SUPPLICANT_INIT_PROPERTY, supp_status, NULL)) { - if (strcmp(supp_status, "stopped") == 0) return -1; - } - - return 0; -} - int wifi_ctrl_recv(char* reply, size_t* reply_len) { int res; int ctrlfd = wpa_ctrl_get_fd(monitor_conn); struct pollfd rfds[2]; + android::wifi_system::SupplicantManager manager; memset(rfds, 0, 2 * sizeof(struct pollfd)); rfds[0].fd = ctrlfd; @@ -360,8 +194,9 @@ int wifi_ctrl_recv(char* reply, size_t* reply_len) { /* timed out, check if supplicant is active * or not .. */ - res = wifi_supplicant_connection_active(); - if (res < 0) return -2; + if (!manager.IsSupplicantRunning()) { + return -2; + } } } while (res == 0); @@ -467,15 +302,15 @@ int wifi_connect_to_supplicant() { } void wifi_close_supplicant_connection() { - char supp_status[PROPERTY_VALUE_MAX] = {'\0'}; int count = 50; /* wait at most 5 seconds to ensure init has stopped stupplicant */ wifi_close_sockets(); + android::wifi_system::SupplicantManager manager; while (count-- > 0) { - if (property_get(SUPPLICANT_INIT_PROPERTY, supp_status, NULL)) { - if (strcmp(supp_status, "stopped") == 0) return; + if (!manager.IsSupplicantRunning()) { + return; } usleep(100000); } |