Android WiFi 起動プロセス (Android S ベース)

この記事では、Android S で WiFi を有効にするプロセスを紹介します。

1. WiFi アクティベーションプロセス

1. フレームワークのプロセス

WifiManager.setWifiEnabled(true) -> WifiServiceImpl.enable(pkgName, true) -> setWifiEnabledInternal(パッケージ名、有効化、callingUid、callingPid、isPrivileged)

-> mSettingsStore.handleWifiToggled(enable) -> Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state) && mPersistWifiState = 状態记下の Wifi 状態态

-> mActiveModeWarden.wifiToggled(new WorkSource(callingUid, packageName)) ここでは、enable の値は関係ありません。

次に、CMD_WIFI_TOGGLED メッセージが ActiveModeWarden 内の WifiController によって処理されます。

Wi-Fi がオンになっている場合、この時点では Wi-Fi は無効になっており、DisabledState によって処理されます。

-> handleStaToggleChangeInDisabledState((WorkSource) msg​​.obj) -> startPrimaryOrScanOnlyClientModeManager(requestorWs) を実行し、直接有効状態に入ります

private boolean startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs) {
    
    
    ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
    if (role == ROLE_CLIENT_PRIMARY) {
    
    
        return startPrimaryClientModeManager(requestorWs);
    } else if (role == ROLE_CLIENT_SCAN_ONLY) {
    
    
        return startScanOnlyClientModeManager(requestorWs);
    } else {
    
    
        return false;
    }
}

private boolean startPrimaryClientModeManager(WorkSource requestorWs) {
    
    
    Log.d(TAG, "Starting primary ClientModeManager in connect mode");
    ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
            new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);
    mClientModeManagers.add(manager);
    mLastPrimaryClientModeManagerRequestorWs = requestorWs;
    return true;
}

Wi-Fi を開きます。対応する役割はROLE_CLIENT_PRIMARYで、startPrimaryClientModeManager() を呼び出します。

このメソッドは、WifiInjector を通じて内部的に新しいConcreteClientModeManager オブジェクトを作成します。ROLE_CLIENT_PRIMARY を に渡したことに注意してください。ConcreteClientModeManager

ConcreteClientModeManager初期化が完了すると、 の構築メソッドは自身に CMD_START メッセージを直接送信し、内部の ClientModeStateMachine ステート マシン< /span>

CMD_START は初期状態 IdleState によって処理されます

// packages/modules/Wifi/service/java/com/android/server/wifi/ConcreteClientModeManager.java
ConcreteClientModeManager.ClientModeStateMachine.IdleState.processMessage(Message message) {
    
    
    switch (message.what) {
    
    
        case CMD_START:
            // 1
            mClientInterfaceName = mWifiNative.setupInterfaceForClientInScanMode(
                                            mWifiNativeInterfaceCallback, roleChangeInfo.requestorWs);
            if (roleChangeInfo.role instanceof ClientConnectivityRole) {
    
    
                // 2
                sendMessage(CMD_SWITCH_TO_CONNECT_MODE, roleChangeInfo);
                transitionTo(mStartedState);
            } else {
    
    
                mScanRoleChangeInfoToSetOnTransition = roleChangeInfo;
                transitionTo(mScanOnlyModeState);
            }
        // ... ...
}

setupInterfaceForClientInScanModeネイティブ レイヤからの iface ステータス コールバックの1 つで渡されますmWifiNativeInterfaceCallback

private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() {
    
    
    @Override
    public void onDestroyed(String ifaceName) {
    
    
        if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) {
    
    
            Log.d(getTag(), "STA iface " + ifaceName + " was destroyed, "
                    + "stopping client mode");

            // we must immediately clean up state in ClientModeImpl to unregister
            // all client mode related objects
            // Note: onDestroyed is only called from the main Wifi thread
            if (mClientModeImpl == null) {
    
    
                Log.w(getTag(), "Received mWifiNativeInterfaceCallback.onDestroyed "
                        + "callback when no ClientModeImpl instance is active.");
            } else {
    
    
                mClientModeImpl.handleIfaceDestroyed();
            }

            sendMessage(CMD_INTERFACE_DESTROYED);
        }
    }

    @Override
    public void onUp(String ifaceName) {
    
    
        if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) {
    
    
            sendMessage(CMD_INTERFACE_STATUS_CHANGED, 1);
        }
    }

    @Override
    public void onDown(String ifaceName) {
    
    
        if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) {
    
    
            sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0);
        }
    }
};

次に、役割に応じて StartedState または ScanOnlyModeState を入力します。StartedState を入力した後、 a> を受け取ります。 IdleState送信済みCMD_SWITCH_TO_CONNECT_MODEメッセージ

// packages/modules/Wifi/service/java/com/android/server/wifi/ConcreteClientModeManager.java
ConcreteClientModeManager.ClientModeStateMachine.StartedState.processMessage(Message message) {
    
    
    switch (message.what) {
    
    
        case CMD_SWITCH_TO_CONNECT_MODE: {
    
    
            updateConnectModeState(roleChangeInfo.role,
                                            WifiManager.WIFI_STATE_ENABLING,
                                            WifiManager.WIFI_STATE_DISABLED);
            // 1
            mWifiNative.switchClientInterfaceToConnectivityMode(mClientInterfaceName, roleChangeInfo.requestorWs)
            mConnectRoleChangeInfoToSetOnTransition = roleChangeInfo;
            transitionTo(mConnectModeState);
        }
        // ... ...
}

switchClientInterfaceToConnectivityMode 成功したら、ConnectModeState と入力し、必要に応じて mClientModeImpl を作成します。

mClientModeImpl は ConnectModeState を終了するときに破棄されることに注意してください。

// packages/modules/Wifi/service/java/com/android/server/wifi/ConcreteClientModeManager.java
ConcreteClientModeManager.ClientModeStateMachine.ConnectModeState.Enter() {
    
    
    mClientModeImpl = mWifiInjector.makeClientModeImpl(
                            mClientInterfaceName, ConcreteClientModeManager.this,
                            mVerboseLoggingEnabled);
    mClientModeImpl.setShouldReduceNetworkScore(mShouldReduceNetworkScore);
}

public void exit() {
    
    
    mClientModeImpl.stop();
    mClientModeImpl = null;
}

この時点で、Wi-Fi は実際に正常に開始され、接続可能な状態に切り替わりました。次のステップは、実際には ClientModeImpl のホームページです。

上記の分析に関与する 3 つのステート マシンは次のとおりです。

  • ActiveModeWarden.WifiController

    上部の WiFi スイッチのステータス (DisabledState/EnabledState) を記録します。

    無効状態 ->有効状態

  • ConcreteClientModeManager.ClientModeStateMachine

    WiFi デバイスのステータス (IdleState/StartedState/ScanOnlyModeState/ConnectModeState)

    アイドル状態 ->開始状態 ->接続モード状態

  • ClientModeImpl

    Wi-Fi接続ステータスを管理する

    切断状態

Framework 層のさまざまな状態遷移はさておき、実際に WiFi を有効にする最終操作は、WifiNative 以下の 2 つのメソッドによって完了します。

/**
     * Setup an interface for client mode (for scan) operations.
     *
     * This method configures an interface in STA mode in the native daemons
     * (wificond, vendor HAL).
     *
     * @param interfaceCallback Associated callback for notifying status changes for the iface.
     * @param requestorWs Requestor worksource.
     * @return Returns the name of the allocated interface, will be null on failure.
     */
public String setupInterfaceForClientInScanMode(
            @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs);

/**
     * Switches an existing Client mode interface from scan mode
     * {@link Iface#IFACE_TYPE_STA_FOR_SCAN} to connectivity mode
     * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY}.
     *
     * @param ifaceName Name of the interface.
     * @param requestorWs Requestor worksource.
     * @return true if the operation succeeded, false if there is an error or the iface is already
     * in scan mode.
     */
public boolean switchClientInterfaceToConnectivityMode(@NonNull String ifaceName,
            @NonNull WorkSource requestorWs);

専門用語で言うと、setupInterfaceForClientInScanMode() メソッドは、ドライバー、ベンダー hal、wificon のロードとインターフェイスの構成を担当します。

switchClientInterfaceToConnectivityMode() メソッドは、サプリカントの開始を担当します。

2.WiFiネイティブ

次に、WifiNative に関連する最も重要な 2 つの機能を紹介します。

2.1 setupInterfaceForClientInScanMode インターフェイスの初期化

最初にスキャンモードを開始します

メインコードは次のとおりです(一部のエラー処理を削除)

// 1. 初始化驱动和vendor hal
startHal();
// 2. 初始化interface
Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
iface.externalListener = interfaceCallback;
iface.name = createStaIface(iface, requestorWs);
// 3. 初始化wificond
mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
                    new NormalScanEventCallback(iface.name),
                    new PnoScanEventCallback(iface.name));

//4. 监听interface的down/up
iface.networkObserver = new NetworkObserverInternal(iface.id);
registerNetworkObserver(iface.networkObserver)

// 5. 启动supplicant监听(但是此时supplicant进程还未启动)
mWifiMonitor.startMonitoring(iface.name);
onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
mWifiVendorHal.enableLinkLayerStats(iface.name);

// 6. 获取芯片支持的wifi feature
iface.featureSet = getSupportedFeatureSetInternal(iface.name);

Wifiネイティブ -> WifiVendorFal ->ハルデバイスマネージャー

2.1.1 ドライバーと WiFi HAL の初期化

先スタータール()

WifiNative.startHal() -> WifiVendorHal.startVendorHal() -> HalDeviceManager.start() -> HalDeviceManager.startWifi()

startWifi() メソッドは実際には 2 行のコードで構成されています

// 通过hal接口启动
WifiStatus status = mWifi.start();
// 获取chip info
WifiChipInfo[] wifiChipInfos = getAllChipInfo();

Wifi.Start()

ハードウェア/インターフェイス/wifi1.6/デフォルト/wifi.cpp

Return<void> Wifi::start(start_cb hidl_status_cb) {
    
    
    return validateAndCall(this, WifiStatusCode::ERROR_UNKNOWN, &Wifi::startInternal,
                           hidl_status_cb);
}

WifiStatus Wifi::startInternal() {
    
    
    // ... ...
    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
    // ... ...
    // Create the chip instance once the HAL is started.
    android::hardware::wifi::V1_0::ChipId chipId = kPrimaryChipId;
    for (auto& hal : legacy_hals_) {
    
    
        chips_.push_back(
                new WifiChip(chipId, chipId == kPrimaryChipId, hal, mode_controller_,
                             std::make_shared<iface_util::WifiIfaceUtil>(iface_tool_, hal),
                             feature_flags_, on_subsystem_restart_callback));
        chipId++;
    }
}

WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
    
    
    // ... ...
    mode_controller_->initialize();				// 加载驱动 driver_tool_->LoadDriver()
    
    legacy_hals_ = legacy_hal_factory_->getHals();
    for (auto& hal : legacy_hals_) {
    
    
        legacy_hal::wifi_error legacy_status = hal->initialize();
        // ... ...
    }
    // ... ...
}

std::vector<std::shared_ptr<WifiLegacyHal>> WifiLegacyHalFactory::getHals() {
    
    
    if (legacy_hals_.empty()) {
    
    
        // 先从已链接的so库中初始化vendor hal的接口(函数指针赋值)
        // 如果失败,证明是多wifi芯片的设备,需要从descriptor.xml初始化
        if (!initVendorHalDescriptorFromLinked()) initVendorHalsDescriptorList();
        for (auto& desc : descs_) {
    
    
            std::shared_ptr<WifiLegacyHal> hal =
                    std::make_shared<WifiLegacyHal>(iface_tool_, desc.fn, desc.primary);
            legacy_hals_.push_back(hal);
        }
    }

    return legacy_hals_;
}

実際には、主に次の手順で構成されます。

  • wifi_mode_controller を介してドライバーをロードする
  • すべての HAL インターフェイスを初期化します (legacy_hal_factory_->getHals())
    • initVendorHalDescriptorFromLinked
    • initVendorHalsDescriptorList

Android S (12) 以降、複数の Wi-Fi チップがサポートされ、HAL レイヤーも変更されました。WiFi HAL 1.5 以降のバージョンでは、複数の Wi-Fi HAL がサポートされています。ベンダーはチップごとに HAL を提供し、xml ファイルを使用します。彼ら。この変更はコミット 2dddd79e1645ea7d2ec41991bd00d6bfe4170ec7 からのものです。

commit 2dddd79e1645ea7d2ec41991bd00d6bfe4170ec7
Author: Jimmy Chen <[email protected]>
Date:   Mon Dec 23 17:50:39 2019 +0200

    Wifi: support multiple WIFI chips
    
    The WIFI HAL API has support for multiple WIFI chips(IWifiChip instances) however the implementation is hard-coded to support only a single WIFI chip. This change reworks the implementation so multiple WIFI chips will be supported.
    Support for multiple chips is based on the concept that each chip is represented by its own vendor HAL library. The implementation will look for descriptor files for vendor HAL libraries under /vendor/etc/wifi/vendor_hals. It will parse descriptors, dynamically load vendor HAL libraries and create WifiLegacyHal and WifiChip objects for each loaded vendor HAL library.
    One of the descriptors should be marked with "primary" flag. The implementation will create the first WifiChip object for this library. Typically it is the one providing the best WIFI functionality, which was previously used as the only WIFI chip.
    Additional support is added inside WifiChip and WifiLegacyHal for getting available chip modes and concurrency combinations from the vendor HAL if available, and allowing the chip to override network interface name when creating interfaces.
    The mechanism for getting chip capabilities is improved to allow getting chip-global capabilities, which are independent of any created interfaces.
    For example, if the framework needs to start a SoftAP on the 60GHz band, it needs to find a chip which supports this band, but before creating any interface on the chip. The new mechanism allows this.
    
    Bug: 146922967
    Test: atest VtsHalWifiV1_0TargetTest VtsHalWifiNanV1_0TargetTest VtsHalWifiApV1_0TargetTest \
                VtsHalWifiV1_1TargetTest \
                VtsHalWifiV1_2TargetTest VtsHalWifiNanV1_2TargetTest \
                VtsHalWifiV1_3TargetTest \
                VtsHalWifiApV1_4TargetTest VtsHalWifiNanV1_4TargetTest VtsHalWifiRttV1_4TargetTest
    Change-Id: Ibdff93ea56aff186d4b5361ac77f6f448a0dfd45

ここで、initVendorHalDescriptorFromLinked と initVendorHalsDescriptorList の 2 つのメソッドを振り返ってみましょう。これは理解しやすいでしょう。

initVendorHalDescriptorFromLinked() メソッドは、リンクされたライブラリ内の init_wifi_vendor_hal_func_table メソッドを見つけて、それを使用して記述子を初期化します。実際、最も重要なことは関数ポインターを初期化することです。

bool WifiLegacyHalFactory::initVendorHalDescriptorFromLinked() {
    
    
    wifi_hal_lib_desc desc;

    if (!initLinkedHalFunctionTable(&desc.fn)) return false;

    desc.primary = true;
    desc.handle = NULL;
    descs_.push_back(desc);
    return true;
}

bool WifiLegacyHalFactory::initLinkedHalFunctionTable(wifi_hal_fn* hal_fn) {
    
    
    init_wifi_vendor_hal_func_table_t initfn;

    // 在已经链接的库中查找 init_wifi_vendor_hal_func_table 方法
    initfn = (init_wifi_vendor_hal_func_table_t)dlsym(RTLD_DEFAULT,
                                                      "init_wifi_vendor_hal_func_table");
    if (!initfn) {
    
    
        LOG(INFO) << "no vendor HAL library linked, will try dynamic load";
        return false;
    }

    // 先给 wifi_hal_fn 对象内部的所有函数指针赋一个空实现,否则会是null,后面上层调用会报错
    if (!initHalFuncTableWithStubs(hal_fn)) {
    
    
        LOG(ERROR) << "Can not initialize the basic function pointer table";
        return false;
    }

    // 这里依赖于vendor提供的legacy_hal实现,一般只是初始化函数指针,可以参考
    // http://aospxref.com/android-13.0.0_r3/xref/hardware/qcom/wlan/qcwcn/wifi_hal/wifi_hal.cpp?r=&mo=17295&fi=547#547
    if (initfn(hal_fn) != WIFI_SUCCESS) {
    
    
        LOG(ERROR) << "Can not initialize the vendor function pointer table";
        return false;
    }

    return true;
}

ライブラリ設定とマルチチップ設定は、libwifi-hal の Android.mk にあります。LIB_WIFI_HAL はレガシー Wi-Fi hal のライブラリです。定義されている場合WIFI_MULTIPLE_VENDOR_HALS、LIB_WIFI_HAL は空ですが、 descriptor.xml 定義が渡される

# Pick a vendor provided HAL implementation library.
# ============================================================
ifeq ($(WIFI_MULTIPLE_VENDOR_HALS), true)
  # vendor HALs are loaded dynamically and not linked here
  LIB_WIFI_HAL :=
else
  LIB_WIFI_HAL ?= libwifi-hal-fallback
  VENDOR_LOCAL_SHARED_LIBRARIES :=
  ifeq ($(BOARD_WLAN_DEVICE), bcmdhd)
    LIB_WIFI_HAL := libwifi-hal-bcm
    VENDOR_LOCAL_SHARED_LIBRARIES := libcrypto
ifneq ($(wildcard vendor/google/libraries/GoogleWifiConfigLib),)
    VENDOR_LOCAL_SHARED_LIBRARIES += \
        google_wifi_firmware_config_version_c_wrapper
endif
  else ifeq ($(BOARD_WLAN_DEVICE), synadhd)
    LIB_WIFI_HAL := libwifi-hal-syna
    VENDOR_LOCAL_SHARED_LIBRARIES := libcrypto
ifneq ($(wildcard vendor/google/libraries/GoogleWifiConfigLib),)
    VENDOR_LOCAL_SHARED_LIBRARIES += \
        google_wifi_firmware_config_version_c_wrapper
endif
  else ifeq ($(BOARD_WLAN_DEVICE), qcwcn)
    LIB_WIFI_HAL := libwifi-hal-qcom
    VENDOR_LOCAL_SHARED_LIBRARIES := libcld80211
    VENDOR_LOCAL_SHARED_LIBRARIES += libcrypto
  else ifeq ($(BOARD_WLAN_DEVICE), mrvl)
    # this is commented because none of the nexus devices
    # that sport Marvell's wifi have support for HAL
    # LIB_WIFI_HAL := libwifi-hal-mrvl
  else ifeq ($(BOARD_WLAN_DEVICE), MediaTek)
    # support MTK WIFI HAL
    LIB_WIFI_HAL := libwifi-hal-mt66xx
  else ifeq ($(BOARD_WLAN_DEVICE), realtek)
    # support Realtek WIFI HAL
    LIB_WIFI_HAL := libwifi-hal-rtk
  else ifeq ($(BOARD_WLAN_DEVICE), emulator)
    LIB_WIFI_HAL := libwifi-hal-emu
  else ifeq ($(BOARD_WLAN_DEVICE), slsi)
    LIB_WIFI_HAL := libwifi-hal-slsi
  endif
endif

# The WiFi HAL that you should be linking.
# ============================================================
include $(CLEAR_VARS)
LOCAL_MODULE := libwifi-hal
LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
LOCAL_LICENSE_CONDITIONS := notice
LOCAL_PROPRIETARY_MODULE := true
LOCAL_CFLAGS := $(wifi_hal_cflags)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := \
    $(LOCAL_PATH)/include
LOCAL_EXPORT_HEADER_LIBRARY_HEADERS := libhardware_legacy_headers
LOCAL_HEADER_LIBRARIES := libhardware_legacy_headers
LOCAL_SHARED_LIBRARIES := \
    libbase \
    libcutils \
    liblog \
    libnl \
    libutils \
    $(VENDOR_LOCAL_SHARED_LIBRARIES)
LOCAL_SRC_FILES := \
    driver_tool.cpp \
    hal_tool.cpp
LOCAL_WHOLE_STATIC_LIBRARIES := $(LIB_WIFI_HAL) libwifi-hal-common
include $(BUILD_SHARED_LIBRARY)

例としてlibwifi-hal-qcomを取り上げます。init_wifi_vendor_hal_func_table()メソッドは次のとおりです。これは、関数ポインタに値を割り当てるだけです。

// hardware/qcom/wlan/qcwcn/wifi_hal/wifi_hal.cpp
/*initialize function pointer table with Qualcomm HAL API*/
wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn) {
    
    
    if (fn == NULL) {
    
    
        return WIFI_ERROR_UNKNOWN;
    }

    fn->wifi_initialize = wifi_initialize;
    fn->wifi_wait_for_driver_ready = wifi_wait_for_driver_ready;
    fn->wifi_cleanup = wifi_cleanup;
    fn->wifi_event_loop = wifi_event_loop;
    fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set;
    fn->wifi_get_concurrency_matrix = wifi_get_concurrency_matrix;
    fn->wifi_set_scanning_mac_oui =  wifi_set_scanning_mac_oui;
    fn->wifi_get_ifaces = wifi_get_ifaces;
    fn->wifi_get_iface_name = wifi_get_iface_name;
    fn->wifi_set_iface_event_handler = wifi_set_iface_event_handler;
    fn->wifi_reset_iface_event_handler = wifi_reset_iface_event_handler;
    fn->wifi_start_gscan = wifi_start_gscan;
    fn->wifi_stop_gscan = wifi_stop_gscan;
    fn->wifi_get_cached_gscan_results = wifi_get_cached_gscan_results;
    fn->wifi_set_bssid_hotlist = wifi_set_bssid_hotlist;
    fn->wifi_reset_bssid_hotlist = wifi_reset_bssid_hotlist;
    fn->wifi_set_significant_change_handler = wifi_set_significant_change_handler;
    fn->wifi_reset_significant_change_handler = wifi_reset_significant_change_handler;
    fn->wifi_get_gscan_capabilities = wifi_get_gscan_capabilities;
    fn->wifi_set_link_stats = wifi_set_link_stats;
    fn->wifi_get_link_stats = wifi_get_link_stats;
    fn->wifi_clear_link_stats = wifi_clear_link_stats;
    fn->wifi_get_valid_channels = wifi_get_valid_channels;
    fn->wifi_rtt_range_request = wifi_rtt_range_request;
    fn->wifi_rtt_range_cancel = wifi_rtt_range_cancel;
    fn->wifi_get_rtt_capabilities = wifi_get_rtt_capabilities;
    fn->wifi_rtt_get_responder_info = wifi_rtt_get_responder_info;
    fn->wifi_enable_responder = wifi_enable_responder;
    fn->wifi_disable_responder = wifi_disable_responder;
    fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag;
    fn->wifi_start_logging = wifi_start_logging;
    fn->wifi_set_epno_list = wifi_set_epno_list;
    fn->wifi_reset_epno_list = wifi_reset_epno_list;
    fn->wifi_set_country_code = wifi_set_country_code;
    fn->wifi_enable_tdls = wifi_enable_tdls;
    fn->wifi_disable_tdls = wifi_disable_tdls;
    fn->wifi_get_tdls_status = wifi_get_tdls_status;
    fn->wifi_get_tdls_capabilities = wifi_get_tdls_capabilities;
    fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump;
    fn->wifi_set_log_handler = wifi_set_log_handler;
    fn->wifi_reset_log_handler = wifi_reset_log_handler;
    fn->wifi_set_alert_handler = wifi_set_alert_handler;
    fn->wifi_reset_alert_handler = wifi_reset_alert_handler;
    fn->wifi_get_firmware_version = wifi_get_firmware_version;
    fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status;
    fn->wifi_get_logger_supported_feature_set = wifi_get_logger_supported_feature_set;
    fn->wifi_get_ring_data = wifi_get_ring_data;
    fn->wifi_get_driver_version = wifi_get_driver_version;
    fn->wifi_set_passpoint_list = wifi_set_passpoint_list;
    fn->wifi_reset_passpoint_list = wifi_reset_passpoint_list;
    fn->wifi_set_lci = wifi_set_lci;
    fn->wifi_set_lcr = wifi_set_lcr;
    fn->wifi_start_sending_offloaded_packet =
            wifi_start_sending_offloaded_packet;
    fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet;
    fn->wifi_start_rssi_monitoring = wifi_start_rssi_monitoring;
    fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring;
    fn->wifi_nan_enable_request = nan_enable_request;
    fn->wifi_nan_disable_request = nan_disable_request;
    fn->wifi_nan_publish_request = nan_publish_request;
    fn->wifi_nan_publish_cancel_request = nan_publish_cancel_request;
    fn->wifi_nan_subscribe_request = nan_subscribe_request;
    fn->wifi_nan_subscribe_cancel_request = nan_subscribe_cancel_request;
    fn->wifi_nan_transmit_followup_request = nan_transmit_followup_request;
    fn->wifi_nan_stats_request = nan_stats_request;
    fn->wifi_nan_config_request = nan_config_request;
    fn->wifi_nan_tca_request = nan_tca_request;
    fn->wifi_nan_beacon_sdf_payload_request = nan_beacon_sdf_payload_request;
    fn->wifi_nan_register_handler = nan_register_handler;
    fn->wifi_nan_get_version = nan_get_version;
    fn->wifi_set_packet_filter = wifi_set_packet_filter;
    fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities;
    fn->wifi_read_packet_filter = wifi_read_packet_filter;
    fn->wifi_nan_get_capabilities = nan_get_capabilities;
    fn->wifi_nan_data_interface_create = nan_data_interface_create;
    fn->wifi_nan_data_interface_delete = nan_data_interface_delete;
    fn->wifi_nan_data_request_initiator = nan_data_request_initiator;
    fn->wifi_nan_data_indication_response = nan_data_indication_response;
    fn->wifi_nan_data_end = nan_data_end;
    fn->wifi_configure_nd_offload = wifi_configure_nd_offload;
    fn->wifi_get_driver_memory_dump = wifi_get_driver_memory_dump;
    fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;
    fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring;
    fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates;
    fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates;
    fn->wifi_get_roaming_capabilities = wifi_get_roaming_capabilities;
    fn->wifi_configure_roaming = wifi_configure_roaming;
    fn->wifi_enable_firmware_roaming = wifi_enable_firmware_roaming;
    fn->wifi_select_tx_power_scenario = wifi_select_tx_power_scenario;
    fn->wifi_reset_tx_power_scenario = wifi_reset_tx_power_scenario;
    fn->wifi_set_radio_mode_change_handler = wifi_set_radio_mode_change_handler;
    fn->wifi_virtual_interface_create = wifi_virtual_interface_create;
    fn->wifi_virtual_interface_delete = wifi_virtual_interface_delete;
    fn->wifi_set_latency_mode = wifi_set_latency_mode;
    fn->wifi_set_thermal_mitigation_mode = wifi_set_thermal_mitigation_mode;
    fn->wifi_set_dtim_config = wifi_set_dtim_config;

    return WIFI_SUCCESS;

ベンダー hal インターフェイスの取得に成功したら、すべてのレガシー hal を初期化します。

hal->initialize();

このメソッドは現在、WIFI_SUCCESS を直接返すだけで何もしません。

// hardware/interface/1.6/default/wifi_legacy_hal.cpp
wifi_error WifiLegacyHal::initialize() {
    LOG(DEBUG) << "Initialize legacy HAL";
    // this now does nothing, since HAL function table is provided
    // to the constructor
    return WIFI_SUCCESS;
}
2.1.2 インターフェースの初期化
// packages/modules/Wifi/service/java/com/android/server/wifi/WifiNative.java
public String setupInterfaceForClientInScanMode(
            @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs) {
    
    
    // ... ...
    Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
    iface.externalListener = interfaceCallback;
    iface.name = createStaIface(iface, requestorWs);
    // ... ...
}

allocateIface()非常に簡単で、WifiNative.IfaceManager を通じて新しい Iface オブジェクトを作成するだけです。

createStaIface、ここisVendorHalSupported 注意する必要はありません。現在検出されているソース コードはすべてサポートされています。実装では、halservice リストに Wi-Fi hal サービスが含まれているかどうかを確認します。

// packages/modules/Wifi/service/java/com/android/server/wifi/WifiNative.java
private String createStaIface(@NonNull Iface iface, @NonNull WorkSource requestorWs) {
    
    
    synchronized (mLock) {
    
    
        if (mWifiVendorHal.isVendorHalSupported()) {
    
    
            return mWifiVendorHal.createStaIface(
                    new InterfaceDestoyedListenerInternal(iface.id), requestorWs);
        } else {
    
    
            Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface.");
            return handleIfaceCreationWhenVendorHalNotSupported(iface);
        }
    }
}

public String createStaIface(@Nullable InterfaceDestroyedListener destroyedListener,
            @NonNull WorkSource requestorWs) {
    
    
    synchronized (sLock) {
    
    
        IWifiStaIface iface = mHalDeviceManager.createStaIface(
                new StaInterfaceDestroyedListenerInternal(destroyedListener), mHalEventHandler,
                requestorWs);
        String ifaceName = mHalDeviceManager.getName((IWifiIface) iface);
        
        // 注册android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback,包括onBackgroundScanFailure,onBackgroundFullScanResult,onBackgroundFullScanResults,onRssiThresholdBreached。注册到wifihal
        registerStaIfaceCallback(iface);
        retrieveWifiChip((IWifiIface) iface);
        
        mIWifiStaIfaces.put(ifaceName, iface);
        return ifaceName;
    }
}

主な分析方法mHalDeviceManager.createStaIface

HalDeviceManager.java

–>createStaIface(CHIP_CAPABILITY_ANY, destroyedListener, handler, requestorWs)

–>createIface(HDM_CREATE_IFACE_STA, CHIP_CAPABILITY_ANY/*requiredChipCapabilities*/, destroyedListener, handler, requestorWs)

private IWifiIface createIface(@HdmIfaceTypeForCreation int createIfaceType,
            long requiredChipCapabilities, InterfaceDestroyedListener destroyedListener,
            Handler handler, WorkSource requestorWs) {
    
    
    synchronized (mLock) {
    
    
        WifiChipInfo[] chipInfos = getAllChipInfo();
        // ... ...
        return createIfaceIfPossible(
                    chipInfos, createIfaceType /* HDM_CREATE_IFACE_STA */, requiredChipCapabilities /* CHIP_CAPABILITY_ANY */,
                    destroyedListener, handler, requestorWs);
    }
}

まずすべてのチップ情報を取得し、createIfaceIfPossible メソッドを通じて最適なチップを選択します。

private IWifiIface createIfaceIfPossible(
            WifiChipInfo[] chipInfos, @HdmIfaceTypeForCreation int createIfaceType /* HDM_CREATE_IFACE_STA */,
            long requiredChipCapabilities/* CHIP_CAPABILITY_ANY */, InterfaceDestroyedListener destroyedListener,
            Handler handler, WorkSource requestorWs) {
    
    
    int targetHalIfaceType = HAL_IFACE_MAP.get(createIfaceType);
    synchronized (mLock) {
    
    
        IfaceCreationData bestIfaceCreationProposal = getBestIfaceCreationProposal(chipInfos,
                    createIfaceType, requiredChipCapabilities, requestorWs);
        if (bestIfaceCreationProposal != null) {
    
    
            IWifiIface iface = executeChipReconfiguration(bestIfaceCreationProposal,
                        createIfaceType /* HDM_CREATE_IFACE_STA */);
            // ... ...
            return iface;
        }
    }
    return null
}

主に次の 2 つの方法があります。

  • getBestIfaceCreationProposal

    最適なifaceを手に入れましょう

    現在は単一のチップを使用しているため、今は分析しません。

  • executeChipReconfiguration

    配置iface

注意深く見るexecuteChipReconfiguration方法

private IWifiIface executeChipReconfiguration(IfaceCreationData ifaceCreationData,
            @HdmIfaceTypeForCreation int createIfaceType) {
    
    
    // ... ...
    switch (createIfaceType) {
    
    
        case HDM_CREATE_IFACE_STA:
            ifaceCreationData.chipInfo.chip.createStaIface(
                    (WifiStatus status, IWifiStaIface iface) -> {
    
    
                        statusResp.value = status;
                        ifaceResp.value = iface;
                    });
            break;
        // ... ...
    }
    // ... ...
    updateRttControllerWhenInterfaceChanges();
    return ifaceResp.value;
}

ifaceCreationData.chipInfo.chip.createStaIface()WiFi HAL は次のように呼ばれます。

// hardware/interfaces/wifi/1.6/default/wifi_chip.cpp
Return<void> WifiChip::createStaIface(createStaIface_cb hidl_status_cb) {
    
    
    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
                           &WifiChip::createStaIfaceInternal, hidl_status_cb);
}

createStaIfaceInternal()以下のステップに分かれています

  • allocateStaIfaceName() プラットフォームのプロパティを通じて構成されたインターフェイス名を取得します。ベンダー hal が wifi_get_supported_iface_name() インターフェイスをサポートしている場合、iface 名は最初にベンダー hal から取得されます。それ以外の場合は、属性 wifi.interface または が使用されます。wifi.interface.0

    device/oneplus/sdm845-common/rootdir/etc/init.qcom.rc: setprop wifi.interface wlan0

  • createVirtualInterface()インターフェイスの作成

    ベンダー hal を呼び出しwifi_virtual_interface_create()、nl80211 インターフェイスを介してインターフェイスを作成します。

    参考 http://aospxref.com/android-13.0.0_r3/xref/hardware/qcom/wlan/qcwcn/wifi_hal/wificonfig.cpp#821

この時点で、Wi-Fi インターフェイスは正常に作成されました。

2.1.3 wificond の初期化

上記の手順 1 と 2 を完了すると、ドライバーと hal が正常にロードされ、インターフェイスが作成されます。

次のステップでは、WifiNl80211ManagersetupInterfaceForClientMode() メソッドを使用して設定します。

public boolean setupInterfaceForClientMode(@NonNull String ifaceName,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) {
    
    
    // 1. 获取 WIFI_NL80211_SERVICE(wifinl80211)
    retrieveWificondAndRegisterForDeath();
    
    // 2. wificond对ifaceName代表的网卡进行初始化,返回了一个ClientInterfaceImpl的代理ClientInterfaceBinder (system/connectivity/wificond/client_interface_binder.cpp)
    IClientInterface clientInterface = mWificond.createClientInterface(ifaceName);
    mClientInterfaces.put(ifaceName, clientInterface);
    
    // 3. subscribeScanEvents, subscribePnoScanEvents
    IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
    mWificondScanners.put(ifaceName, wificondScanner);
    canEventHandler scanEventHandler = new ScanEventHandler(executor, scanCallback);
    mScanEventHandlers.put(ifaceName,  scanEventHandler);
    wificondScanner.subscribeScanEvents(scanEventHandler);
    PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(executor,
            pnoScanCallback);
    mPnoScanEventHandlers.put(ifaceName,  pnoScanEventHandler);
    wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
}

wificond (wifi 接続デーモン) は現在、ネットワーク カードの構成とスキャンのみをサポートしており、接続は引き続き wpa_supplicant を介して行われます。

wificond のコードはここでは展開されません。中心となるのは、Wi-Fi ハードウェアを管理し、Wi-Fi 関連の情報と制御機能を提供するために使用されるネットリンクを介してカーネル nl80211 モジュールと通信することです。

この時点で、1、2、3 のドライバーと HAL がロードされ、ネットワーク カードが正常に作成および初期化され、主に Wi-Fi とスキャンの管理を担当する wificond モジュールも正常に初期化されました。

では、なぜ setupInterfaceForClientInScanMode と呼ばれるのでしょうか? これまでのところ、上位層への接続機能は提供できず、スキャンのみを提供するためです。

次のステップでは、接続機能を提供する wpa_supplicant プロセスを開始します。

2.2 switchClientInterfaceToConnectivityMode 启アニメーション サプリカント

// packages/modules/Wifi/service/java/com/android/server/wifi/WifiNative.java
public boolean switchClientInterfaceToConnectivityMode(@NonNull String ifaceName,
            @NonNull WorkSource requestorWs) {
    
    
    // ... ...
    startSupplicant();
    // ... ...
    mSupplicantStaIfaceHal.setupIface(iface.name);
    // ... ...
}
2.2.1 サプリカントの開始

startSupplicant() --> startAndWaitForSupplicantConnection()

private boolean startAndWaitForSupplicantConnection() {
    
    
    // Start initialization if not already started.
    if (!mSupplicantStaIfaceHal.isInitializationStarted()
            && !mSupplicantStaIfaceHal.initialize()) {
    
    
        return false;
    }

    if (!mSupplicantStaIfaceHal.startDaemon()) {
    
    
        Log.e(TAG, "Failed to startup supplicant");
        return false;
    }
    boolean connected = false;
    int connectTries = 0;
    while (!connected && connectTries++ < CONNECT_TO_SUPPLICANT_RETRY_TIMES) {
    
    
        // Check if the initialization is complete.
        connected = mSupplicantStaIfaceHal.isInitializationComplete();
        if (connected) {
    
    
            break;
        }
        try {
    
    
            Thread.sleep(CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS);
        } catch (InterruptedException ignore) {
    
    
        }
    }
    return connected;
}

この関数は非常に単純です。mSupplicantStaIfaceHal.startDaemon() を呼び出してサプリカントを開始します。その後、CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS 100 ミリ秒ごとにメソッド < を通じて最大 50 回チェックします。 /span>< a i=3>サプリカントが正常に起動したかどうかを確認します。 mSupplicantStaIfaceHal.isInitializationComplete()

Supplicant アニメーション: SupplicantStaIfaceHal.startDaemon() --> ISupplicantStaIfaceHal.startDaemon() -->サプリカントStaIfaceハルエイドルImpl

// packages/modules/Wifi/service/java/com/android/server/wifi/SupplicantStaIfaceHalAidlImpl.java    
public boolean startDaemon() {
    
    
    final String methodStr = "startDaemon";
    if (mISupplicant != null) {
    
    
        Log.i(TAG, "Service is already initialized, skipping " + methodStr);
        return true;
    }

    mISupplicant = getSupplicantMockable();
    if (mISupplicant == null) {
    
    
        Log.e(TAG, "Unable to obtain ISupplicant binder.");
        return false;
    }
    Log.i(TAG, "Obtained ISupplicant binder.");

    try {
    
    
        IBinder serviceBinder = getServiceBinderMockable();
        if (serviceBinder == null) {
    
    
            return false;
        }
        serviceBinder.linkToDeath(mSupplicantDeathRecipient, /* flags= */  0);
        return true;
    } catch (RemoteException e) {
    
    
        handleRemoteException(e, methodStr);
        return false;
    }
}

メインメソッドgetSupplicantMockable()

private static final String HAL_INSTANCE_NAME = ISupplicant.DESCRIPTOR + "/default";

protected ISupplicant getSupplicantMockable() {
    
    
    synchronized (mLock) {
    
    
        try {
    
    
            return ISupplicant.Stub.asInterface(
                    ServiceManager.waitForDeclaredService(HAL_INSTANCE_NAME));
        } catch (Exception e) {
    
    
            Log.e(TAG, "Unable to get ISupplicant service, " + e);
            return null;
        }
    }
}

サプリカントのサービス名を展開しますandroid.hardware.wifi.supplicant.ISupplicant/default。wpa_supplicant は Wi-Fi が閉じられた後に終了するため、この時点で再度開いたときにサービスが見つからないため、システムは引き上げます

09-12 17:09:38.988   645   645 I servicemanager: Found android.hardware.wifi.supplicant.ISupplicant/default in device VINTF manifest.
09-12 17:09:38.988   645   645 I servicemanager: Since 'android.hardware.wifi.supplicant.ISupplicant/default' could not be found, trying to start it as a lazy AIDL service
09-12 17:09:38.514     0     0 I init    : starting service 'wpa_supplicant'...
09-12 17:09:38.527     0     0 I init    : Control message: Processed ctl.interface_start for 'aidl/android.hardware.wifi.supplicant.ISupplicant/default' from pid: 645 (/system/bin/servicemanager)

サプリカントhalのrcファイル(/vendor/etc/init/android.hardware.wifi.supplicant-service.rc)は以下のように定義されています

service wpa_supplicant /vendor/bin/hw/wpa_supplicant \
        -O/data/vendor/wifi/wpa/sockets -dd \
        -g@android:wpa_wlan0
        #   we will start as root and wpa_supplicant will switch to user wifi
        #   after setting up the capabilities required for WEXT
        #   user wifi
        #   group wifi inet keystore
        interface aidl android.hardware.wifi.supplicant.ISupplicant/default
        class main
        socket wpa_wlan0 dgram 660 wifi wifi
        disabled
        oneshot

現時点では、SupplicantStaIfaceHalAidlImpl は supplicant プロセスを正常に開始し、サプリカント hal サービスにバインドしています。後でサプリカントと通信する必要がある場合、フレームワーク層は SupplicantStaIfaceHalAidlImpl を通じてそのインターフェイスを直接呼び出すことができます。

3. ClientModeImpl がスキャンを開始します

初期状態 DisconnectedState になった直後に接続スキャンを開始します。

DisconnectedState.enter() {
    
    
    mWifiConnectivityManager.handleConnectionStateChanged(
            mClientModeManager,
            WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
}

切断時の handleConnectionStateChanged メソッドの動作を見てみましょう

public void handleConnectionStateChanged(
            ConcreteClientModeManager clientModeManager, int state) {
    
    
    if (mWifiState == WIFI_STATE_DISCONNECTED) {
    
    
        scheduleWatchdogTimer();
        // Switch to the disconnected scanning schedule
        setSingleScanningSchedule(mDisconnectedSingleScanScheduleSec);
        setSingleScanningType(mDisconnectedSingleScanType);
        startConnectivityScan(SCAN_IMMEDIATELY);
    }
}

mDisconnectedSingleScanScheduleSec: デフォルト {20, 40, 80, 160}、config_wifiDisconnectedScanIntervalScheduleSec を通じてカスタマイズ可能

mDisconnectedSingleScanType: 默认WifiScanner.SCAN_TYPE_HIGH_ACCURACY

最後に、startConnectivityScan() インターフェイスを呼び出して、スキャンを直接開始します。

4. ステートマシンプロセス

WiFi がオンになるとステート マシンが変化します

5. まとめ

追加予定

おすすめ

転載: blog.csdn.net/weixin_40588186/article/details/132837372