(五十九)Android O WiFi启动流程梳理续——enableSupplicant

前言:之前在 (四十四)Android O WiFi启动流程梳理 梳理到了WifiNative的enableSupplicant ,没有继续梳理下去,现在接着梳理。


1.wpa_supplicant的简单介绍

wpa_supplicant是一个开源项目,它实现了station对无线网络的管理和控制功能,根据官方描述,它支持的功能很多,比如:1.支持WPAIEEE802.11i所定义的大部分功能;2.支持多种EAPMethod3.对多种无线网卡和驱动的支持等等。

具体请参考:

1.Linux WPA/WPA2/IEEE 802.1X Supplicant

2.wpa_supplicant及wpa_cli使用方法


2. 流程梳理


2.1 WifiNative

    /**
    * Enable wpa_supplicant via wificond.
    * @return Returns true on success.
    */
    public boolean enableSupplicant() {
        return mWificondControl.enableSupplicant();
    }


2.2 WificondControl

    /**
    * Enable wpa_supplicant via wificond.
    * @return Returns true on success.
    */
    public boolean enableSupplicant() {
        if (mClientInterface == null) {
            Log.e(TAG, "No valid wificond client interface handler");
            return false;
        }

        try {
            return mClientInterface.enableSupplicant();
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to enable supplicant due to remote exception");
        }
        return false;
    }

mClientInterface在之前的(五十七)Android O WiFi的扫描流程梳理续——梳理java与c++之间的aidl-cpp通信

梳理过了,对应实现是client_interface_binder

    public IClientInterface setupDriverForClientMode() {
        Log.d(TAG, "Setting up driver for client mode");
        mWificond = mWifiInjector.makeWificond();
        if (mWificond == null) {
            Log.e(TAG, "Failed to get reference to wificond");
            return null;
        }

        IClientInterface clientInterface = null;
        try {
            clientInterface = mWificond.createClientInterface();
        } catch (RemoteException e1) {
            Log.e(TAG, "Failed to get IClientInterface due to remote exception");
            return null;
        }

        if (clientInterface == null) {
            Log.e(TAG, "Could not get IClientInterface instance from wificond");
            return null;
        }
        Binder.allowBlocking(clientInterface.asBinder());

        // Refresh Handlers
        mClientInterface = clientInterface;



2.3 client_interface_binder

Status ClientInterfaceBinder::enableSupplicant(bool* success) {
  *success = impl_ && impl_->EnableSupplicant();
  return Status::ok();
}
而impl_对应的是client_interface_impl



2.4 client_interface_impl

bool ClientInterfaceImpl::EnableSupplicant() {
  return supplicant_manager_->StartSupplicant();
}

而supplicant_manager_是在client_interface_impl的构造函数中初始化的

ClientInterfaceImpl::ClientInterfaceImpl(
    uint32_t wiphy_index,
    const std::string& interface_name,
    uint32_t interface_index,
    const std::vector<uint8_t>& interface_mac_addr,
    InterfaceTool* if_tool,
    SupplicantManager* supplicant_manager,
    NetlinkUtils* netlink_utils,
    ScanUtils* scan_utils)
    : wiphy_index_(wiphy_index),
      interface_name_(interface_name),
      interface_index_(interface_index),
      interface_mac_addr_(interface_mac_addr),
      if_tool_(if_tool),
      supplicant_manager_(supplicant_manager),

client_interface_impl的构造函数之前分析过,是在server里调用的

Status Server::createClientInterface(sp<IClientInterface>* created_interface) {
  InterfaceInfo interface;
  if (!SetupInterface(&interface)) {
    return Status::ok();  // Logging was done internally
  }

  unique_ptr<ClientInterfaceImpl> client_interface(new ClientInterfaceImpl(
      wiphy_index_,
      interface.name,
      interface.index,
      interface.mac_address,
      if_tool_.get(),
      supplicant_manager_.get(),
      netlink_utils_,
      scan_utils_));
  *created_interface = client_interface->GetBinder();
  client_interfaces_.push_back(std::move(client_interface));
  BroadcastClientInterfaceReady(client_interfaces_.back()->GetBinder());

  return Status::ok();
}


2.5 supplicant_manager_

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

可以观察到这个方法会先检查配置文件是否存在

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;

看最后的注释:

      /*
       * property serial updated means that init process is scheduled
       * after we sched_yield, further property status checking is based on this
       */
表示调用了sched_yield后start wpa_supplicant的任务就进入时刻表中,后续基于此进行属性状态检查

流程先梳理到这里吧。。。



3. 总结



猜你喜欢

转载自blog.csdn.net/sinat_20059415/article/details/80956631