Android Q WIFI开启流程

Android Q WIFI开启流程

一、点击wifi开关
默认有2种方式打开wifi
1)从设置打开
\packages\apps\Settings\src\com\android\settings\wifi\WifiEnabler.java
调用了WifiManager的setWifiEnabled

    @Override
    public boolean onSwitchToggled(boolean isChecked) {
        //Do nothing if called as a result of a state machine event
        if (mStateMachineEvent) {
            return true;
        }
        // Show toast message if Wi-Fi is not allowed in airplane mode
        if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
            Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
            // Reset switch to off. No infinite check/listener loop.
            mSwitchWidget.setChecked(false);
            return false;
        }

        if (isChecked) {
            mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_WIFI_ON);
        } else {
            // Log if user was connected at the time of switching off.
            mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_WIFI_OFF,
                    mConnected.get());
        }
        if (!mWifiManager.setWifiEnabled(isChecked)) {
            // Error
            mSwitchWidget.setEnabled(true);
            Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
        }
        return true;
    }

2)从状态栏点击打开
\frameworks\base\packages\SystemUI\src\com\android\systemui\qs\tiles\WifiTile.java
mController.setWifiEnabled

    @Override
    protected void handleClick() {
        // Secondary clicks are header clicks, just toggle.
        mState.copyTo(mStateBeforeClick);
        boolean wifiEnabled = mState.value;
        // Immediately enter transient state when turning on wifi.
        refreshState(wifiEnabled ? null : ARG_SHOW_TRANSIENT_ENABLING);
        mController.setWifiEnabled(!wifiEnabled);
        mExpectDisabled = wifiEnabled;
        if (mExpectDisabled) {
            mHandler.postDelayed(() -> {
                if (mExpectDisabled) {
                    mExpectDisabled = false;
                    refreshState();
                }
            }, QSIconViewImpl.QS_ANIM_LENGTH);
        }
    }

\frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\NetworkControllerImpl.java
调用了WifiManager的setWifiEnabled

    @Override
    public void setWifiEnabled(final boolean enabled) {
        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... args) {
                mWifiManager.setWifiEnabled(enabled);
                return null;
            }
        }.execute();
    }

两种方法最后都是调用的WifiManager.setWifiEnabled方法

二、AndroidQ 默认加入了支持双WiFi的代码。这里打开WiFi就提供了俩个接口
frameworks/base/wifi/java/android/net/wifi/WifiManager.java
正常打开WiFi是调用这个单参的函数。

    @Deprecated
    public boolean setWifiEnabled(boolean enabled) {
        try {
            return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

在service中调用setWifiEnabled 会默认传入 staId为STA_PRIMARY来调用setWifiEnabled2方法
这个方法是用来指定staId的
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

    @Override
    public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
        return setWifiEnabled2(packageName, STA_PRIMARY, enable);
    }
    @Override
    public synchronized boolean setWifiEnabled2(String packageName, int staId,boolean enable) {
        if (enforceChangePermission(packageName) != MODE_ALLOWED) {
            return false;
        }
        boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid());
        if (!isPrivileged && !isDeviceOrProfileOwner(Binder.getCallingUid(), packageName)
                && !mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q,
                  Binder.getCallingUid())
                && !isSystem(packageName, Binder.getCallingUid())) {
            mLog.info("setWifiEnabled not allowed for uid=%")
                    .c(Binder.getCallingUid()).flush();
            return false;
        }
        // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
        if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
            mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
            return false;
        }

        // If SoftAp is enabled, only privileged apps are allowed to toggle wifi
        if (!isPrivileged && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {
            mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush();
            return false;
        }

        mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
                .c(Binder.getCallingUid()).c(enable).flush();
        long ident = Binder.clearCallingIdentity();
        try {
            if (staId == STA_PRIMARY && !mSettingsStore.handleWifiToggled(enable)) {
                // Nothing to do if wifi cannot be toggled
                return true;
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        if (mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) {
            if (enable) {
                mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON);
            } else {
                WifiInfo wifiInfo = mClientModeImpl.syncRequestConnectionInfo();
                mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_OFF,
                        wifiInfo == null ? -1 : wifiInfo.getNetworkId());
            }
        }

        if (!mIsControllerStarted) {
            Log.e(TAG,"WifiController is not yet started, abort setWifiEnabled");
            return false;
        }

        mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
		if(staId == STA_PRIMARY)
            mActiveModeWarden.wifiToggled();
		else if(staId == STA_SECONDARY && (getNumConcurrentStaSupported() > 1) && (getWifiEnabledState() == WifiManager.WIFI_STATE_ENABLED))
			mActiveModeWarden.qtiWifiToggled(staId, enable);
        else
            Log.e(TAG,"setWifiEnabled not allowed for Id: " + staId);
        return true;
    }

三、看到SetWifiEnabled2方法中调用了mActiveModeWarden.wifiToggled();
\frameworks\opt\net\wifi\service\java\com\android\server\wifi\ActiveModeWarden.java

    public void wifiToggled() {
        mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED);
	}

发送了CMD_WIFI_TOGGLED消息通知状态改变

四、WifiController处理消息
WifiController是ActiveModeWarden.java中的一个内部类是一个状态机
因为是开启流程 所以目前默认状态是DisabledState

	@Override
	public boolean processMessageFiltered(Message msg) {
	     switch (msg.what) {
	         case CMD_WIFI_TOGGLED:
	         case CMD_SCAN_ALWAYS_MODE_CHANGED:
	             if (shouldEnableSta()) {
	                 startClientModeManager();
	                 transitionTo(mEnabledState);
	             }
	             break;
	         //省略
	    }
	}

调用了startClientModeManager()方法 来启动一个新的客户端管理。

    /**
     * Method to enable a new client mode manager.
     */
    private boolean startClientModeManager() {
        Log.d(TAG, "Starting ClientModeManager");
        ClientListener listener = new ClientListener();
        ClientModeManager manager = mWifiInjector.makeClientModeManager(listener);
        listener.setActiveModeManager(manager);
        manager.start();
        if (!switchClientModeManagerRole(manager)) {
            manager.stop();
            return false;
        }
        mActiveModeManagers.add(manager);
        return true;
    }

五、ClientModeManager.start()
\frameworks\opt\net\wifi\service\java\com\android\server\wifi\ClientModeManager.java

    /**
     * Start client mode.
     */
    @Override
    public void start() {
        Log.d(TAG, "Starting with role ROLE_CLIENT_SCAN_ONLY");
        mRole = ROLE_CLIENT_SCAN_ONLY;
        mTargetRole = ROLE_CLIENT_SCAN_ONLY;
        mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
    }

start()方法发送了CMD_START 这个消息
ClientModeStateMachine是一个状态机 因为第一次打开WIFI所以默认是IdleState

 @Override
 public boolean processMessage(Message message) {
     switch (message.what) {
         case CMD_START:
             // Always start in scan mode first.
             mClientInterfaceName =
                     mWifiNative.setupInterfaceForClientInScanMode(
                     mWifiNativeInterfaceCallback);
             if (TextUtils.isEmpty(mClientInterfaceName)) {
                 Log.e(TAG, "Failed to create ClientInterface. Sit in Idle");
                 mModeListener.onStartFailure();
                 break;
             }
             transitionTo(mScanOnlyModeState);
             break;
         default:
             Log.d(TAG, "received an invalid message: " + message);
             return NOT_HANDLED;
     }
     return HANDLED;
 }

六、mWifiNative.setupInterfaceForClientInScanMode()
\frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiNative.java

    /**
     * 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.
     * @return Returns the name of the allocated interface, will be null on failure.
     */
    public String setupInterfaceForClientInScanMode(
            @NonNull InterfaceCallback interfaceCallback) {
        synchronized (mLock) {
            if (!startHal()) {
                Log.e(TAG, "Failed to start Hal");
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
                return null;
            }
            Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
            if (iface == null) {
                Log.e(TAG, "Failed to allocate new STA iface");
                return null;
            }
            iface.externalListener = interfaceCallback;
            iface.name = createStaIface(iface);
            if (TextUtils.isEmpty(iface.name)) {
                Log.e(TAG, "Failed to create iface in vendor HAL");
                mIfaceMgr.removeIface(iface.id);
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
                return null;
            }
            if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
                    new NormalScanEventCallback(iface.name),
                    new PnoScanEventCallback(iface.name))) {
                Log.e(TAG, "Failed to setup iface in wificond=" + iface.name);
                teardownInterface(iface.name);
                mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
                return null;
            }
            iface.networkObserver = new NetworkObserverInternal(iface.id);
            if (!registerNetworkObserver(iface.networkObserver)) {
                Log.e(TAG, "Failed to register network observer for iface=" + iface.name);
                teardownInterface(iface.name);
                return null;
            }
            mWifiMonitor.startMonitoring(iface.name);
            // Just to avoid any race conditions with interface state change callbacks,
            // update the interface state before we exit.
            onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
            Log.i(TAG, "Successfully setup " + iface);

            iface.featureSet = getSupportedFeatureSetInternal(iface.name);
            return iface.name;
        }
    }

1)WifiNative 这里首先去打开HAL

    /** Helper method invoked to start supplicant if there were no ifaces */
    private boolean startHal() {
        synchronized (mLock) {
            if (!mIfaceMgr.hasAnyIface()) {
                if (mWifiVendorHal.isVendorHalSupported()) {
                    if (!mWifiVendorHal.startVendorHal()) {
                        Log.e(TAG, "Failed to start vendor HAL");
                        return false;
                    }
                } else {
                    Log.i(TAG, "Vendor Hal not supported, ignoring start.");
                }
            }
            return true;
        }
    }

mWifiVendorHal.startVendorHal()
\frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiVendorHal.java

    /**
     * Bring up the HIDL Vendor HAL.
     * @return true on success, false otherwise.
     */
    public boolean startVendorHal() {
        synchronized (sLock) {
            if (!mHalDeviceManager.start()) {
                mLog.err("Failed to start vendor HAL").flush();
                return false;
            }
            mLog.info("Vendor Hal started successfully").flush();
            return true;
        }
    }

mHalDeviceManager.start()
\frameworks\opt\net\wifi\service\java\com\android\server\wifi\HalDeviceManager.java

    /**
     * Attempts to start Wi-Fi (using HIDL). Returns the success (true) or failure (false) or
     * the start operation. Will also dispatch any registered ManagerStatusCallback.onStart() on
     * success.
     *
     * Note: direct call to HIDL.
     */
    public boolean start() {
        return startWifi();
    }

    private boolean startWifi() {
        if (VDBG) Log.d(TAG, "startWifi");
        initIWifiIfNecessary();
        synchronized (mLock) {
            try {
                if (mWifi == null) {
                    Log.w(TAG, "startWifi called but mWifi is null!?");
                    return false;
                } else {
                    int triedCount = 0;
                    while (triedCount <= START_HAL_RETRY_TIMES) {
                        WifiStatus status = mWifi.start();
                        if (status.code == WifiStatusCode.SUCCESS) {
                            initIWifiChipDebugListeners();
                            managerStatusListenerDispatch();
                            if (triedCount != 0) {
                                Log.d(TAG, "start IWifi succeeded after trying "
                                         + triedCount + " times");
                            }
                            return true;
                        } else if (status.code == WifiStatusCode.ERROR_NOT_AVAILABLE) {
                            // Should retry. Hal might still be stopping.
                            Log.e(TAG, "Cannot start IWifi: " + statusString(status)
                                    + ", Retrying...");
                            try {
                                Thread.sleep(START_HAL_RETRY_INTERVAL_MS);
                            } catch (InterruptedException ignore) {
                                // no-op
                            }
                            triedCount++;
                        } else {
                            // Should not retry on other failures.
                            Log.e(TAG, "Cannot start IWifi: " + statusString(status));
                            return false;
                        }
                    }
                    Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times");
                    return false;
                }
            } catch (RemoteException e) {
                Log.e(TAG, "startWifi exception: " + e);
                return false;
            }
        }
    }

mWifi.start()方法是启动实际加载WiFi动作的调用,这里涉及HIDL机制调用。通过获取IWifi接口对象,调用其方法。这里IWifi接口对象是IWifi.hal文件中实现。

hardware\interfaces\wifi\1.0\IWifi.hal 通过编译生成对应的java文件生成在
out\soong\.intermediates\hardware\interfaces\wifi\1.0\android.hardware.wifi-V1.0-java_gen_java\gen\srcs\android\hardware\wifi\V1_0\IWifi.java

@Override
public android.hardware.wifi.V1_0.WifiStatus start()
        throws android.os.RemoteException {
    android.os.HwParcel _hidl_request = new android.os.HwParcel();
    _hidl_request.writeInterfaceToken(android.hardware.wifi.V1_0.IWifi.kInterfaceName);

    android.os.HwParcel _hidl_reply = new android.os.HwParcel();
    try {
        mRemote.transact(3 /* start */, _hidl_request, _hidl_reply, 0 /* flags */);
        _hidl_reply.verifySuccess();
        _hidl_request.releaseTemporaryStorage();

        android.hardware.wifi.V1_0.WifiStatus _hidl_out_status = new android.hardware.wifi.V1_0.WifiStatus();
        ((android.hardware.wifi.V1_0.WifiStatus) _hidl_out_status).readFromParcel(_hidl_reply);
        return _hidl_out_status;
    } finally {
        _hidl_reply.release();
    }
}

通过binder调用到wifi.cpp的start方法
hardware\interfaces\wifi\1.4\default\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() {
    if (run_state_ == RunState::STARTED) {
        return createWifiStatus(WifiStatusCode::SUCCESS);
    } else if (run_state_ == RunState::STOPPING) {
        return createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE,
                                "HAL is stopping");
    }
    WifiStatus wifi_status = initializeModeControllerAndLegacyHal();
    if (wifi_status.code == WifiStatusCode::SUCCESS) {
        // Create the chip instance once the HAL is started.
        chip_ = new WifiChip(kChipId, legacy_hal_, mode_controller_,
                             iface_util_, feature_flags_);
        run_state_ = RunState::STARTED;
        for (const auto& callback : event_cb_handler_.getCallbacks()) {
            if (!callback->onStart().isOk()) {
                LOG(ERROR) << "Failed to invoke onStart callback";
            };
        }
        LOG(INFO) << "Wifi HAL started";
    } else {
        for (const auto& callback : event_cb_handler_.getCallbacks()) {
            if (!callback->onFailure(wifi_status).isOk()) {
                LOG(ERROR) << "Failed to invoke onFailure callback";
            }
        }
        LOG(ERROR) << "Wifi HAL start failed";
        // Clear the event callback objects since the HAL start failed.
        event_cb_handler_.invalidate();
    }
    return wifi_status;
}

WifiStatus Wifi::initializeModeControllerAndLegacyHal() {
    if (!mode_controller_->initialize()) {
        LOG(ERROR) << "Failed to initialize firmware mode controller";
        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
    }
    legacy_hal::wifi_error legacy_status = legacy_hal_->initialize();
    if (legacy_status != legacy_hal::WIFI_SUCCESS) {
        LOG(ERROR) << "Failed to initialize legacy HAL: "
                   << legacyErrorToString(legacy_status);
        return createWifiStatusFromLegacyError(legacy_status);
    }
    return createWifiStatus(WifiStatusCode::SUCCESS);
}

mode_controller_->initialize()
hardware\interfaces\wifi\1.4\default\wifi_mode_controller.cpp

bool WifiModeController::initialize() {
    if (!driver_tool_->LoadDriver()) {
        LOG(ERROR) << "Failed to load WiFi driver";
        return false;
    }
    return true;
}

driver_tool_->LoadDriver()
frameworks\opt\net\wifi\libwifi_hal\driver_tool.cpp

bool DriverTool::LoadDriver() {
  return ::wifi_load_driver() == 0;
}

frameworks\opt\net\wifi\libwifi_hal\wifi_hal_common.cpp

int wifi_load_driver() {
#ifdef WIFI_DRIVER_MODULE_PATH
  if (is_wifi_driver_loaded()) {
    return 0;
  }

  if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) return -1;
#endif

#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
  if (is_wifi_driver_loaded()) {
    return 0;
  }

  if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0) {
#ifdef WIFI_DRIVER_MODULE_PATH
    PLOG(WARNING) << "Driver unloading, err='fail to change driver state'";
    if (rmmod(DRIVER_MODULE_NAME) == 0) {
      PLOG(DEBUG) << "Driver unloaded";
    } else {
      // Set driver prop to "ok", expect HL to restart Wi-Fi.
      PLOG(DEBUG) << "Driver unload failed! set driver prop to 'ok'.";
      property_set(DRIVER_PROP_NAME, "ok");
    }
#endif
    return -1;
  }
#endif
  is_driver_loaded = true;
  return 0;
}

到此startHal() 调用结束

2)mWifiCondManager.setupInterfaceForClientMode
frameworks\base\wifi\java\android\net\wifi\nl80211\WifiNl80211Manager.java

    /**
     * Set up an interface for client (STA) mode.
     *
     * @param ifaceName Name of the interface to configure.
     * @param executor The Executor on which to execute the callbacks.
     * @param scanCallback A callback for framework initiated scans.
     * @param pnoScanCallback A callback for PNO (offloaded) scans.
     * @return true on success.
     */
    public boolean setupInterfaceForClientMode(@NonNull String ifaceName,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) {
        Log.d(TAG, "Setting up interface for client mode");
        if (!retrieveWificondAndRegisterForDeath()) {
            return false;
        }

        if (scanCallback == null || pnoScanCallback == null || executor == null) {
            Log.e(TAG, "setupInterfaceForClientMode invoked with null callbacks");
            return false;
        }

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

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

        // Refresh Handlers
        mClientInterfaces.put(ifaceName, clientInterface);
        try {
            IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
            if (wificondScanner == null) {
                Log.e(TAG, "Failed to get WificondScannerImpl");
                return false;
            }
            mWificondScanners.put(ifaceName, wificondScanner);
            Binder.allowBlocking(wificondScanner.asBinder());
            ScanEventHandler 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);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
        }

        return true;
    }

这个方法主要作用是为了底层添加了一下接口.createClientInterface

七、之后回到了IdelState 继续执行transitionTo(mScanOnlyModeState);
这个作用是将状态机的状态置成ScanOnlyModeState

状态机初始化状态如下
ClientModeStateMachine(Looper looper) {
    super(TAG, looper);

    // CHECKSTYLE:OFF IndentationCheck
    addState(mIdleState);
    addState(mStartedState, mIdleState);
    addState(mScanOnlyModeState, mStartedState);
    addState(mConnectModeState, mStartedState);
    // CHECKSTYLE:ON IndentationCheck

    setInitialState(mIdleState);
    start();
}
所以状态机会按照下面的方法执行
IdleState.exit()->StartedState.enter()->StartedState.exit()->ScanOnlyModeState.enter()

这个之后回到了第四步 start()之后
继续执行switchClientModeManagerRole()

/**
 * Method to switch a client mode manager mode of operation (from ScanOnly To Connect &
 * vice-versa) based on the toggle state.
 */
private boolean switchClientModeManagerRole(@NonNull ClientModeManager modeManager) {
    if (mSettingsStore.isWifiToggleEnabled()) {
        modeManager.setRole(ActiveModeManager.ROLE_CLIENT_PRIMARY);
    } else if (checkScanOnlyModeAvailable()) {
        modeManager.setRole(ActiveModeManager.ROLE_CLIENT_SCAN_ONLY);
    } else {
        Log.e(TAG, "Something is wrong, no client mode toggles enabled");
        return false;
    }
    return true;
}

查看isWifiToggleEnabled
frameworks\opt\net\wifi\service\java\com\android\server\wifi\WifiSettingsStore.java

public synchronized boolean isWifiToggleEnabled() {
    if (mAirplaneModeOn) {
        return mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE;
    } else {
        return mPersistWifiState != WIFI_DISABLED;//需要判断这个值
    }
}

在setWifiEnabled2的时候会调用handleWifiToggled
public synchronized boolean handleWifiToggled(boolean wifiEnabled) {
    // Can Wi-Fi be toggled in airplane mode ?
    if (mAirplaneModeOn && !isAirplaneToggleable()) {
        return false;
    }

    if (wifiEnabled) {
        if (mAirplaneModeOn) {
            persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
        } else {
            persistWifiState(WIFI_ENABLED); //因为没有打开飞行模式所以会走到这里
        }
    } else {
        // When wifi state is disabled, we do not care
        // if airplane mode is on or not. The scenario of
        // wifi being disabled due to airplane mode being turned on
        // is handled handleAirplaneModeToggled()
        persistWifiState(WIFI_DISABLED);
    }
    return true;
}

private void persistWifiState(int state) {
    final ContentResolver cr = mContext.getContentResolver();
    mPersistWifiState = state;//将这个是变成了WIFI_ENABLED
    Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);
}

所以isWifiToggleEnabled这个方法在此返回了ture

因此执行modeManager.setRole(ActiveModeManager.ROLE_CLIENT_PRIMARY);

@Override
public void setRole(@Role int role) {
    Preconditions.checkState(CLIENT_ROLES.contains(role));
    if (role == ROLE_CLIENT_SCAN_ONLY) {
        mTargetRole = role;
        // Switch client mode manager to scan only mode.
        mStateMachine.sendMessage(ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE);
    } else if (CLIENT_CONNECTIVITY_ROLES.contains(role)) {
        mTargetRole = role;
        // Switch client mode manager to connect mode.
        mStateMachine.sendMessage(ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE, role);
    }
}
//CLIENT_CONNECTIVITY_ROLES 定义在 ActiveModeManager.java中
List<Integer> CLIENT_CONNECTIVITY_ROLES = Arrays.asList(
        ROLE_CLIENT_PRIMARY,
        ROLE_CLIENT_SECONDARY,
        ROLE_CLIENT_LOCAL_ONLY);
ROLE_CLIENT_PRIMARY包含在CLIENT_CONNECTIVITY_ROLES 数组中
所以会执行 mStateMachine.sendMessage(ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE, role);

查看发现有 StartedState 和ConnectModeState状态处理 CMD_SWITCH_TO_CONNECT_MODE消息
但是现在还没有到ConnectModeState状态所以会由StartedState 处理

 @Override
 public boolean processMessage(Message message) {
     switch(message.what) {
         case CMD_START:
             // Already started, ignore this command.
             break;
         case CMD_SWITCH_TO_CONNECT_MODE:
             mRole = message.arg1; // could be any one of possible connect mode roles.
             updateConnectModeState(WifiManager.WIFI_STATE_ENABLING,
                     WifiManager.WIFI_STATE_DISABLED);
             if (!mWifiNative.switchClientInterfaceToConnectivityMode(
                     mClientInterfaceName)) {
                 updateConnectModeState(WifiManager.WIFI_STATE_UNKNOWN,
                         WifiManager.WIFI_STATE_ENABLING);
                 updateConnectModeState(WifiManager.WIFI_STATE_DISABLED,
                         WifiManager.WIFI_STATE_UNKNOWN);
                 mModeListener.onStartFailure();
                 break;
             }
             transitionTo(mConnectModeState);
             break;
        //省略
    }
}

mWifiNative.switchClientInterfaceToConnectivityMode

/**
 * 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.
 * @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) {
    synchronized (mLock) {
        final Iface iface = mIfaceMgr.getIface(ifaceName);
        if (iface == null) {
            Log.e(TAG, "Trying to switch to connectivity mode on an invalid iface="
                    + ifaceName);
            return false;
        }
        if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) {
            Log.e(TAG, "Already in connectivity mode on iface=" + ifaceName);
            return true;
        }
        if (!startSupplicant()) {
            Log.e(TAG, "Failed to start supplicant");
            teardownInterface(iface.name);
            mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
            return false;
        }
        if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
            Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
            teardownInterface(iface.name);
            mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
            return false;
        }
        iface.type = Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY;
        iface.featureSet = getSupportedFeatureSetInternal(iface.name);
        Log.i(TAG, "Successfully switched to connectivity mode on iface=" + iface);
        return true;
    }
}

启动了startSupplicant

/** Helper method invoked to start supplicant if there were no STA ifaces */
private boolean startSupplicant() {
    synchronized (mLock) {
        if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) {
            if (!startAndWaitForSupplicantConnection()) {
                Log.e(TAG, "Failed to connect to supplicant");
                return false;
            }
            if (!mSupplicantStaIfaceHal.registerDeathHandler(
                    new SupplicantDeathHandlerInternal())) {
                Log.e(TAG, "Failed to register supplicant death handler");
                return false;
            }
        }
        return true;
    }
}

/**
 * This method is called to wait for establishing connection to wpa_supplicant.
 *
 * @return true if connection is established, false otherwise.
 */
private boolean startAndWaitForSupplicantConnection() {//在这里等待与supplicant建立连接
    // 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()
frameworks\opt\net\wifi\service\java\com\android\server\wifi\SupplicantStaIfaceHal.java

/**
 * Start the supplicant daemon.
 *
 * @return true on success, false otherwise.
 */
public boolean startDaemon() {
    synchronized (mLock) {
        if (isV1_1()) {
            Log.i(TAG, "Starting supplicant using HIDL");
            return startDaemon_V1_1();
        } else {
            Log.i(TAG, "Starting supplicant using init");
            mFrameworkFacade.startSupplicant();
            return true;
        }
    }
}

/**
 * Start the supplicant daemon for V1_1 service.
 *
 * @return true on success, false otherwise.
 */
private boolean startDaemon_V1_1() {
    synchronized (mLock) {
        try {
            // This should startup supplicant daemon using the lazy start HAL mechanism.
            getSupplicantMockableV1_1();
        } catch (RemoteException e) {
            Log.e(TAG, "Exception while trying to start supplicant: "
                    + e);
            supplicantServiceDiedHandler(mDeathRecipientCookie);
            return false;
        } catch (NoSuchElementException e) {
            // We're starting the daemon, so expect |NoSuchElementException|.
            Log.d(TAG, "Successfully triggered start of supplicant using HIDL");
        }
        return true;
    }
}

protected android.hardware.wifi.supplicant.V1_1.ISupplicant getSupplicantMockableV1_1()
        throws RemoteException, NoSuchElementException {
    synchronized (mLock) {
        android.hardware.wifi.supplicant.V1_1.ISupplicant iSupplicantDerived =
                android.hardware.wifi.supplicant.V1_1.ISupplicant.castFrom(
                        getSupplicantMockable());
        if (iSupplicantDerived == null) {
            throw new NoSuchElementException("Cannot cast to V1.1 service.");
        }
        return iSupplicantDerived;
    }
}

protected ISupplicant getSupplicantMockable() throws RemoteException, NoSuchElementException {
    synchronized (mLock) {
        ISupplicant iSupplicant = ISupplicant.getService();
        if (iSupplicant == null) {
            throw new NoSuchElementException("Cannot get root service.");
        }
        return iSupplicant;
    }
}

ISupplicant.getService(); 这个也是通过HIDL实现

out\soong\.intermediates\hardware\interfaces\wifi\supplicant\1.0\android.hardware.wifi.supplicant-V1.0-java_gen_java\gen\srcs\android\hardware\wifi\supplicant\V1_0\ISupplicant.java
/**
 * Warning: this will not wait for the interface to come up if it hasn't yet started. See getService(String,boolean) instead.
 */
public static ISupplicant getService() throws android.os.RemoteException {
    return getService("default");
}

/**
 * Warning: this will not wait for the interface to come up if it hasn't yet
 * started. See getService(String,boolean) instead.
 */
public static ISupplicant getService(String serviceName) throws android.os.RemoteException {
    return ISupplicant.asInterface(android.os.HwBinder.getService("[email protected]::ISupplicant", serviceName));
}

八、 在这个方法中将触发启动wpa_supplicant进程,这里需要注意,在manifest.xml中对其需要进行配置,运行时会将服务名称注册到hwservicemanager中。

wpa_supplicant目录下文件调用:

external\wpa_supplicant_8\wpa_supplicant\main.c
external\wpa_supplicant_8\wpa_supplicant\wpa_supplicant.c
external\wpa_supplicant_8\wpa_supplicant\notify.c
external\wpa_supplicant_8\wpa_supplicant\hidl\1.3\hidl.cpp
external\wpa_supplicant_8\wpa_supplicant\hidl\1.3\hidl_manager.cpp
out\soong\.intermediates\hardware\interfaces\wifi\supplicant\1.3\android.hardware.wifi.supplicant@1.3_genc++\gen\android\hardware\wifi\supplicant\1.3\SupplicantAll.cpp
system\libhidl\transport\ServiceManagement.cpp
system\hwservicemanager\ServiceManager.cpp

main.c -> main() ==> main.c -> wpa_supplicant_init() 
==> wpa_supplicant.c -> wpa_supplicant_init() ==> notify.c -> wpas_notify_supplicant_initialized() 
==> hidl.cpp -> wpas_hidl_init() ==> hidl_manager.cpp -> registerHidlService() 
==> SupplicantAll.cpp -> registerAsService() ==> ServiceManagement.cpp -> registerAsServiceInternal() 
==> ServiceManager.cpp -> addWithChain() ==> ServiceManager.cpp -> addImpl()
==> ServiceManager.cpp -> sendPackageRegistrationNotification() 
==> onRegistration(fqName, instanceName, false /* preexisting */) 触发回调

在SupplicantStaIfaceHal.java 初始化的时候注册了回调的监听

/**
 * Registers a service notification for the ISupplicant service, which triggers initialization
 * of the ISupplicantStaIface
 * @return true if the service notification was successfully registered
 */
public boolean initialize() {
    synchronized (mLock) {
        if (mVerboseLoggingEnabled) {
            Log.i(TAG, "Registering ISupplicant service ready callback.");
        }
        mISupplicant = null;
        mISupplicantVendor = null;
        mISupplicantStaIfaces.clear();
        mISupplicantVendorStaIfaces.clear();
        if (mIServiceManager != null) {
            // Already have an IServiceManager and serviceNotification registered, don't
            // don't register another.
            return true;
        }
        try {
            mIServiceManager = getServiceManagerMockable();
            if (mIServiceManager == null) {
                Log.e(TAG, "Failed to get HIDL Service Manager");
                return false;
            }
            if (!linkToServiceManagerDeath()) {
                return false;
            }
            /* TODO(b/33639391) : Use the new ISupplicant.registerForNotifications() once it
               exists */
            if (!mIServiceManager.registerForNotifications(
                    ISupplicant.kInterfaceName, "default", mServiceNotificationCallback)) {
                Log.e(TAG, "Failed to register for notifications to "
                        + ISupplicant.kInterfaceName);
                mIServiceManager = null; // Will need to register a new ServiceNotification
                return false;
            }
        } catch (RemoteException e) {
            Log.e(TAG, "Exception while trying to register a listener for ISupplicant service: "
                    + e);
            supplicantServiceDiedHandler(mDeathRecipientCookie);
        }
        return true;
    }
}

private final IServiceNotification mServiceNotificationCallback =
        new IServiceNotification.Stub() {
    public void onRegistration(String fqName, String name, boolean preexisting) {
        synchronized (mLock) {
            if (mVerboseLoggingEnabled) {
                Log.i(TAG, "IServiceNotification.onRegistration for: " + fqName
                        + ", " + name + " preexisting=" + preexisting);
            }
            if (!initSupplicantService()) {
                Log.e(TAG, "initalizing ISupplicant failed.");
                supplicantServiceDiedHandler(mDeathRecipientCookie);
            } else {
                Log.i(TAG, "Completed initialization of ISupplicant.");
            }
        }
    }
};

private boolean initSupplicantService() {
    synchronized (mLock) {
        try {
            mISupplicant = getSupplicantMockable();
        } catch (RemoteException e) {
            Log.e(TAG, "ISupplicant.getService exception: " + e);
            return false;
        } catch (NoSuchElementException e) {
            Log.e(TAG, "ISupplicant.getService exception: " + e);
            return false;
        }

        if (mISupplicant == null) {
            Log.e(TAG, "Got null ISupplicant service. Stopping supplicant HIDL startup");
            return false;
        }
        if (!linkToSupplicantDeath(mSupplicantDeathRecipient, ++mDeathRecipientCookie)) {
            return false;
        }
    }
    if (!initSupplicantVendorService())
        Log.e(TAG, "Failed to init SupplicantVendor service");
    return true;
}

到此supplicant已经启动

九、switchClientInterfaceToConnectivityMode 之后会继续执行mSupplicantStaIfaceHal.setupIface(iface.name) 来设置接口,完成后打印

Log.i(TAG, "Successfully switched to connectivity mode on iface=" + iface);

十、StartedState 继续处理 CMD_SWITCH_TO_CONNECT_MODE 消息
执行transitionTo(mConnectModeState); 方法 进入 ConnectModeState状态

@Override
public void enter() {
    Log.d(TAG, "entering ConnectModeState");
    mClientModeImpl.registerModeListener(mClientModeImplListener);
    mClientModeImpl.setOperationalMode(ClientModeImpl.CONNECT_MODE,
            mClientInterfaceName);
}

继续处理CMD_SWITCH_TO_CONNECT_MODE 消息
@Override
public boolean processMessage(Message message) {
    switch (message.what) {
        //省略
        case CMD_SWITCH_TO_CONNECT_MODE:
            int newRole = message.arg1;
            // Already in connect mode, only switching the connectivity roles.
            if (newRole != mRole) {
                mRole = newRole;
                mModeListener.onStarted();
            }
            break;
        //省略
     }
}
触发onStarted()回调

onStarted()在ActiveModeWarden.java中定义

private class ClientListener extends ModeCallback implements ActiveModeManager.Listener {
   @Override
   public void onStarted() {
       updateClientScanMode();
       updateBatteryStats();
   }

   @Override
   public void onStopped() {
       mActiveModeManagers.remove(getActiveModeManager());
       updateClientScanMode();
       updateBatteryStats();
       mWifiController.sendMessage(WifiController.CMD_STA_STOPPED);
   }

   @Override
   public void onStartFailure() {
       mActiveModeManagers.remove(getActiveModeManager());
       updateClientScanMode();
       updateBatteryStats();
       mWifiController.sendMessage(WifiController.CMD_STA_START_FAILURE);
   }
}

然后执行updateClientScanMode

// Update the scan state based on all active mode managers.
private void updateClientScanMode() {
    boolean scanEnabled = hasAnyClientModeManager();
    boolean scanningForHiddenNetworksEnabled;

    if (mContext.getResources().getBoolean(R.bool.config_wifiScanHiddenNetworksScanOnlyMode)) {
        scanningForHiddenNetworksEnabled = hasAnyClientModeManager();
    } else {
        scanningForHiddenNetworksEnabled = hasAnyClientModeManagerInConnectivityRole();
    }
    mScanRequestProxy.enableScanning(scanEnabled, scanningForHiddenNetworksEnabled);
}

mScanRequestProxy.enableScanning()
frameworks\opt\net\wifi\service\java\com\android\server\wifi\ScanRequestProxy.java

private void enableScanningInternal(boolean enable) {
    if (!retrieveWifiScannerIfNecessary()) {
        Log.e(TAG, "Failed to retrieve wifiscanner");
        return;
    }
    mWifiScanner.setScanningEnabled(enable);
    sendScanAvailableBroadcast(mContext, enable);
    clearScanResults();
    Log.i(TAG, "Scanning is " + (enable ? "enabled" : "disabled"));
}

private void enableScanningInternal(boolean enable) {
    if (!retrieveWifiScannerIfNecessary()) {
        Log.e(TAG, "Failed to retrieve wifiscanner");
        return;
    }
    mWifiScanner.setScanningEnabled(enable);
    sendScanAvailableBroadcast(mContext, enable);
    clearScanResults();
    Log.i(TAG, "Scanning is " + (enable ? "enabled" : "disabled"));
}

mWifiScanner.setScanningEnabled
frameworks\base\wifi\java\android\net\wifi\WifiScanner.java

/**
 * Enable/Disable wifi scanning.
 *
 * @param enable set to true to enable scanning, set to false to disable all types of scanning.
 *
 * @see WifiManager#ACTION_WIFI_SCAN_AVAILABILITY_CHANGED
 * {@hide}
 */
@SystemApi
@RequiresPermission(Manifest.permission.NETWORK_STACK)
public void setScanningEnabled(boolean enable) {
    validateChannel();
    mAsyncChannel.sendMessage(enable ? CMD_ENABLE : CMD_DISABLE);
}

之后就可就是开始扫描AP

你可能感兴趣的:(android,wifi)