(九十五)Android O wpa_supplicant.conf配置文件探究

参考:https://blog.csdn.net/kris_fei/article/details/73650602

 

1.wpa_supplicant.conf简介

首先说下源码位置,与wpa_supplicant.conf相关的配置文件、脚本如下红框标注处。

其中wpa_supplicant.conf 不是手机中的wpa_supplicant.conf,打开看一下是wpa_supplicant.conf的配置说明。

##### Example wpa_supplicant configuration file ###############################
#
# This file describes configuration file format and lists all available option.
# Please also take a look at simpler configuration examples in 'examples'
# subdirectory.
#
# Empty lines and lines starting with # are ignored

# NOTE! This file may contain password information and should probably be made
# readable only by root user on multiuser systems.

# Note: All file paths in this configuration file should use full (absolute,
# not relative to working directory) path in order to allow working directory
# to be changed. This can happen if wpa_supplicant is run in the background.

# Whether to allow wpa_supplicant to update (overwrite) configuration
#
# This option can be used to allow wpa_supplicant to overwrite configuration
# file whenever configuration is changed (e.g., new network block is added with
# wpa_cli or wpa_gui, or a password is changed). This is required for
# wpa_cli/wpa_gui to be able to store the configuration changes permanently.
# Please note that overwriting configuration file will remove the comments from
# it.
#update_config=1

简单翻译一下,wpa_supplicant.conf是wpa_supplicant.conf配置文件的一个例子,这个文件描述了配置文件格式以及列举了所有的可选选项。请看一下在examples文件夹下的例子。

请注意文件有可能包含密码信息,所以尽可能地在多用户系统中将这个文件设为root用户只读。

注意,所有这个文件中的路径请用绝对路径,不用用相对路径,只是为了允许工作目录可以改变。在supplicant运行在后台时有可能会发生这个事情。

 

那顺势看下wpa_supplicant.conf在example的例子吧:

是指这个么

 

2. 探讨wpa_supplicant.conf由来

2.1 wpa_supplicant_conf.mk

# Include this makefile to generate your hardware specific wpa_supplicant.conf
# Requires: WIFI_DRIVER_SOCKET_IFACE

LOCAL_PATH := $(call my-dir)

########################
include $(CLEAR_VARS)

LOCAL_MODULE := wpa_supplicant.conf
LOCAL_MODULE_CLASS := ETC 
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/wifi

include $(BUILD_SYSTEM)/base_rules.mk

WPA_SUPPLICANT_CONF_TEMPLATE := $(LOCAL_PATH)/wpa_supplicant_template.conf
WPA_SUPPLICANT_CONF_SCRIPT := $(LOCAL_PATH)/wpa_supplicant_conf.sh
$(LOCAL_BUILT_MODULE): PRIVATE_WIFI_DRIVER_SOCKET_IFACE := $(WIFI_DRIVER_SOCKET_IFACE)
$(LOCAL_BUILT_MODULE): PRIVATE_WPA_SUPPLICANT_CONF_TEMPLATE := $(WPA_SUPPLICANT_CONF_TEMPLATE)
$(LOCAL_BUILT_MODULE): PRIVATE_WPA_SUPPLICANT_CONF_SCRIPT := $(WPA_SUPPLICANT_CONF_SCRIPT)
$(LOCAL_BUILT_MODULE) : $(WPA_SUPPLICANT_CONF_TEMPLATE) $(WPA_SUPPLICANT_CONF_SCRIPT)
    @echo Target wpa_supplicant.conf: $@
    @mkdir -p $(dir $@)
    $(hide) WIFI_DRIVER_SOCKET_IFACE="$(PRIVATE_WIFI_DRIVER_SOCKET_IFACE)" \
        bash $(PRIVATE_WPA_SUPPLICANT_CONF_SCRIPT) $(PRIVATE_WPA_SUPPLICANT_CONF_TEMPLATE) > $@

########################

先看一下mk文件,模块名直接就是wpa_supplicant.conf,试着make一下

ninja: no work to do.
ninja: no work to do.
wildcard(out/target/product/generic_x86_64/clean_steps.mk) was changed, regenerating...
$(shell uname -rsm) was changed, regenerating...
[526/824] including system/sepolicy/Android.mk ...
system/sepolicy/Android.mk:79: warning: BOARD_SEPOLICY_VERS not specified, assuming current platform version
[824/824] including tools/tradefederation/core/Android.mk ...
[ 93% 14/15] glob tools/metalava/src/main/java/**/*.kt
ninja: error: unknown target 'wpa_supplicant.conf'
10:28:42 ninja failed with: exit status 1

#### failed to build some targets (02:08 (mm:ss)) ####

emmm,本地编译有点问题,编译其他的是可以的,待续

还是回头来看下mk文件,其中用到了两个其他的文件,分别是wpa_supplicant_template.conf 和 wpa_supplicant_conf.sh

脚本+文件最后生成在$(TARGET_OUT_VENDOR)/etc/wifi目录下的wpa_supplicant.conf

LOCAL_MODULE := wpa_supplicant.conf
LOCAL_MODULE_CLASS := ETC 
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/wifi

可以看手机的vendor/etc/wifi下看到该文件

另外在/data/misc/wifi下也有该文件

 

2.2 wpa_supplicant_template.conf

jiatai@jiatai:~/expand/aosp/aosp/external/wpa_supplicant_8/wpa_supplicant$ cat wpa_supplicant_template.conf
##### wpa_supplicant configuration file template #####
update_config=1
eapol_version=1
ap_scan=1
fast_reauth=1
pmf=1
p2p_add_cli_chan=1

 

2.3 wpa_supplicant_conf.sh

jiatai@jiatai:~/expand/aosp/aosp/external/wpa_supplicant_8/wpa_supplicant$ cat wpa_supplicant_conf.sh
#!/bin/bash
#
# Copyright (C) 2010 The Android Open Source Project
#
# This software may be distributed under the terms of the BSD license.
# See README for more details.
#

# Generate a wpa_supplicant.conf from the template.
# $1: the template file name
if [ -n "$WIFI_DRIVER_SOCKET_IFACE" ]
then
  sed -e 's/#.*$//' -e 's/[ \t]*$//' -e '/^$/d' < $1 | sed -e "s/wlan0/$WIFI_DRIVER_SOCKET_IFACE/"
else
  sed -e 's/#.*$//' -e 's/[ \t]*$//' -e '/^$/d' < $1
fi

学习一下sed命令的功能。

sed
作用:主要用于替换指定的字符;查找或替换指定字符串时,必须把字符串用//来注释下,比如root 必须是/root/;
sed 只要不适用-i参数,一般都是在输出终端上显示而已,无法更改源文件;

参数-e: --expression,多重编辑;
参数-n:不带-n则列出文件所有内容,加上-n只列出结果sed特殊处理的那一行;
参数-i:直接修改读取的内容文件,而不是输出到终端;
功能s:替换、取代;
功能d:删除;
功能a:新增;

如上命令应该是去除注释、去除空格、去除空行,替换wlan0为WIFI_DRIVER_SOCKET_IFACE

执行下看下效果

自己写个例子试下

空格、tab键、空格+tab键的单独行,末尾不要加字符也试了下,会被删除。

 

2.4 supplicant启动流程

回头在看下五十九)Android O WiFi启动流程梳理续——enableSupplicant 启动流程中与wpa_supplicant_conf的关系。

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);

  /*
   * 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;
}

关注下如下代码

  /* 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;
  }

看下对应常量声明

const char kSupplicantInitProperty[] = "init.svc.wpa_supplicant";
const char kSupplicantConfigTemplatePath[] =
    "/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;

如下是确保配置文件存在的逻辑代码

  1. 尝试对/data/misc/wifi/wpa_supplicant.conf其进行读写,如果已经有该文件则返回,不能读写的话尝试改写读写权限。
  2. 先看下/system/etc/wifi有没有配置文件,没有的话再看下vendor/etc/wifi
  3. 打开/data/misc/wifi/wpa_supplicant.conf
  4. 将etc/wifi下的配置文件拷贝到/data/misc/wifi/wpa_supplicant.conf
  5. 修改权限用户组
int ensure_config_file_exists(const char* config_file) {
  char buf[2048];
  int srcfd, destfd;
  int nread;
  int ret;
  std::string templatePath;

  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;
  }

  std::string configPathSystem =
      std::string("/system") + std::string(kSupplicantConfigTemplatePath);
  std::string configPathVendor =
      std::string("/vendor") + std::string(kSupplicantConfigTemplatePath);
  srcfd = TEMP_FAILURE_RETRY(open(configPathSystem.c_str(), O_RDONLY));
  templatePath = configPathSystem;
  if (srcfd < 0) {
    int errnoSystem = errno;
    srcfd = TEMP_FAILURE_RETRY(open(configPathVendor.c_str(), O_RDONLY));
    templatePath = configPathVendor;
    if (srcfd < 0) {
      int errnoVendor = errno;
      LOG(ERROR) << "Cannot open \"" << configPathSystem << "\": "
                 << strerror(errnoSystem);
      LOG(ERROR) << "Cannot open \"" << configPathVendor << "\": "
                 << strerror(errnoVendor);
      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 \"" << templatePath
                 << "\": " << 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;
}

到这里也梳理完了如下两个配置文件的由来。

  1. /data/misc/wifi/wpa_supplicant.conf
  2. /vendor/etc/wifi/wpa_supplicant.conf

 

3. 总结

/vendor/etc/wifi/wpa_supplicant.conf 这个配置文件是由wpa_supplicant下的wpa_supplicant_template.conf作简单处理生成的。

/data/misc/wifi/wpa_supplicant.conf是在supplicant第一次启动的时候由/vendor/etc/wifi/wpa_supplicant.conf 拷贝过来的。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值