Wifi模块—源码分析Wifi热点的开启(Android P)

一 前言
        Android使用一个修改版wpa_supplicant作为daemon来控制WIFI,它是一个安全中间件,代码位于external/wpa_supplicant,为各种无线网卡提供统一的安全机制。当然在这里只是介绍一下wpa_supplicant和 hostapd,研究分析的部分主要还是应用层和java框架层,有时也会涉及Native层。

wpa_supplicant_8主要有三个子目录 :

       hostapd:当手机进入Soft AP模式时,手机将扮演AP的角色,需要hostapd来提供AP的功能,也就是wifi热点的实现。

       wpa_supplicant:Station模式,也叫Managed模式,这是平时最常见的使用wifi连接AP的情况。

       src:hostapd和wpa_supplicant中都包含一些通用的数据结构和处理方法,这些内容都放在此src目录中。

 

二 图示调用流程


 

三、 具体代码流程


       Android P之后,Wifi模块增加了packages/apps/Settings/src/com/android/settings/wifi/tether/路径,相当于把Wifi热点独立放到了tether文件夹下面,并添加了WifiTetherSettings.java类,对应着Wifi热点的界面,而Android P之前是没有的,Wifi热点界面之前是对应在TetherSettings的一部分,有些厂商也还是会改到TetherSettings上。

1 、packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSettings.java

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    // Assume we are in a SettingsActivity. This is only safe because we currently use
    // SettingsActivity as base for all preference fragments.
    final SettingsActivity activity = (SettingsActivity) getActivity();
    final SwitchBar switchBar = activity.getSwitchBar();
    mSwitchBarController = new WifiTetherSwitchBarController(activity,
            new SwitchBarController(switchBar));
    getLifecycle().addObserver(mSwitchBarController);
    switchBar.show();
}

初始化mSwitchBarController,这个类含有SwitchBar的实例。

2、 packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java

public class WifiTetherSwitchBarController implements SwitchWidgetController.OnSwitchChangeListener,
        LifecycleObserver, OnStart, OnStop, DataSaverBackend.Listener {}

3、 packages/apps/Settings/src/com/android/settings/widget/SwitchWidgetController.java

/**
* Interface definition for a callback to be invoked when the switch has been toggled.
*/
public interface OnSwitchChangeListener {
    /**
    * Called when the checked state of the Switch has changed.
    *
    * @param isChecked The new checked state of switchView.
    *
    * @return true to update the state of the switch with the new value.
    */
    boolean onSwitchToggled(boolean isChecked);
}

4、 packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java

@Override
public boolean onSwitchToggled(boolean isChecked) {
    if (!isChecked) {
        stopTether();
    } else if (!mWifiManager.isWifiApEnabled()) {
        startTether();
    }
    return true;
}
startTether()。

void startTether() {
    mSwitchBar.setEnabled(false);
    mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
            mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
}

       android O开始通过mConnectivityManager.startTethering来启动热点了,之前都是通过WifiManager的setWifiApEnable的方法,该方法现在也已废弃。

5 、frameworks/base/core/java/android/net/ConnectivityManager.java

/**
* Convenient overload for
* {@link #startTethering(int, boolean, OnStartTetheringCallback, Handler)} which passes a null
* handler to run on the current thread's {@link Looper}.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void startTethering(int type, boolean showProvisioningUi,
        final OnStartTetheringCallback callback) {
    startTethering(type, showProvisioningUi, callback, null);
}
startTethering。

/**
* Runs tether provisioning for the given type if needed and then starts tethering if
* the check succeeds. If no carrier provisioning is required for tethering, tethering is
* enabled immediately. If provisioning fails, tethering will not be enabled. It also
* schedules tether provisioning re-checks if appropriate.
*
* @param type The type of tethering to start. Must be one of
*         {@link ConnectivityManager.TETHERING_WIFI},
*         {@link ConnectivityManager.TETHERING_USB}, or
*         {@link ConnectivityManager.TETHERING_BLUETOOTH}.
* @param showProvisioningUi a boolean indicating to show the provisioning app UI if there
*         is one. This should be true the first time this function is called and also any time
*         the user can see this UI. It gives users information from their carrier about the
*         check failing and how they can sign up for tethering if possible.
* @param callback an {@link OnStartTetheringCallback} which will be called to notify the caller
*         of the result of trying to tether.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
public void startTethering(int type, boolean showProvisioningUi,
        final OnStartTetheringCallback callback, Handler handler) {
    Preconditions.checkNotNull(callback, "OnStartTetheringCallback cannot be null.");
 
    ResultReceiver wrappedCallback = new ResultReceiver(handler) {
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            if (resultCode == TETHER_ERROR_NO_ERROR) {
                callback.onTetheringStarted();
            } else {
                callback.onTetheringFailed();
            }
        }
    };
 
    try {
        String pkgName = mContext.getOpPackageName();
        Log.i(TAG, "startTethering caller:" + pkgName);
        mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
    } catch (RemoteException e) {
        Log.e(TAG, "Exception trying to start tethering.", e);
        wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
    }
}

内部抽象类OnStartTetheringCallback。

/**
* Callback for use with {@link #startTethering} to find out whether tethering succeeded.
* @hide
*/
@SystemApi
public static abstract class OnStartTetheringCallback {
    /**
    * Called when tethering has been successfully started.
    */
    public void onTetheringStarted() {};
 
    /**
    * Called when starting tethering failed.
    */
    public void onTetheringFailed() {};
}

6、 frameworks/base/services/core/java/com/android/server/ConnectivityService.java

@Override
public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
        String callerPkg) {
    ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
    if (!isTetheringSupported()) {
        receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
        return;
    }
    mTethering.startTethering(type, receiver, showProvisioningUi);
}

7、 frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java

public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
    if (!isTetherProvisioningRequired()) {
        enableTetheringInternal(type, true, receiver);
        return;
    }
 
    if (showProvisioningUi) {
        runUiTetherProvisioningAndEnable(type, receiver);
    } else {
        runSilentTetherProvisioningAndEnable(type, receiver);
    }
}

enableTetheringInternal。

/**
* Enables or disables tethering for the given type. This should only be called once
* provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
* for the specified interface.
*/
private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
    boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
    int result;
    switch (type) {
        case TETHERING_WIFI:
            result = setWifiTethering(enable);
            if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
                scheduleProvisioningRechecks(type);
            }
            sendTetherResult(receiver, result);
            break;
        case TETHERING_USB:
            result = setUsbTethering(enable);
            if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
                scheduleProvisioningRechecks(type);
            }
            sendTetherResult(receiver, result);
            break;
        case TETHERING_BLUETOOTH:
            setBluetoothTethering(enable, receiver);
            break;
        default:
            Log.w(TAG, "Invalid tether type.");
            sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
    }
}

setWifiTethering。

private int setWifiTethering(final boolean enable) {
    int rval = TETHER_ERROR_MASTER_ERROR;
    final long ident = Binder.clearCallingIdentity();
    try {
        synchronized (mPublicSync) {
            mWifiTetherRequested = enable;
            final WifiManager mgr = getWifiManager();
            if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
                (!enable && mgr.stopSoftAp())) {
                rval = TETHER_ERROR_NO_ERROR;
            }
        }
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
    return rval;
}

mgr.startSoftAp。

8 、frameworks/base/wifi/java/android/net/wifi/WifiManager.java

/**
* Start SoftAp mode with the specified configuration.
* Note that starting in access point mode disables station
* mode operation
* @param wifiConfig SSID, security and channel details as
*        part of WifiConfiguration
* @return {@code true} if the operation succeeds, {@code false} otherwise
*
* @hide
*/
public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
    try {
        return mService.startSoftAp(wifiConfig);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

startSoftAp。

9、 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

/**
* see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
* @param wifiConfig SSID, security and channel details as part of WifiConfiguration
* @return {@code true} if softap start was triggered
* @throws SecurityException if the caller does not have permission to start softap
*/
@Override
public boolean startSoftAp(WifiConfiguration wifiConfig) {
    // NETWORK_STACK is a signature only permission.
    enforceNetworkStackPermission();
 
    mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
 
    synchronized (mLocalOnlyHotspotRequests) {
        // If a tethering request comes in while we have LOHS running (or requested), call stop
        // for softap mode and restart softap with the tethering config.
        if (!mLocalOnlyHotspotRequests.isEmpty()) {
            stopSoftApInternal();
        }
        return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
    }
}

startSoftApInternal。

/**
* Internal method to start softap mode. Callers of this method should have already checked
* proper permissions beyond the NetworkStack permission.
*/
private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
    mLog.trace("startSoftApInternal uid=% mode=%")
            .c(Binder.getCallingUid()).c(mode).flush();
 
    // null wifiConfig is a meaningful input for CMD_SET_AP
    if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
        SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
        mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
        return true;
    }
    Slog.e(TAG, "Invalid WifiConfiguration");
    return false;
}

mWifiController.sendMessage。

10、 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java

public class WifiController extends StateMachine
WifiController是个状态机,看看它的初始状态。

WifiController(Context context, WifiStateMachine wsm, Looper wifiStateMachineLooper,
                WifiSettingsStore wss, Looper wifiServiceLooper, FrameworkFacade f,
                WifiStateMachinePrime wsmp) {
    super(TAG, wifiServiceLooper);
    mFacade = f;
    mContext = context;
    mWifiStateMachine = wsm;
    mWifiStateMachineLooper = wifiStateMachineLooper;
    mWifiStateMachinePrime = wsmp;
    mSettingsStore = wss;
 
    // CHECKSTYLE:OFF IndentationCheck
    addState(mDefaultState);
        addState(mStaDisabledState, mDefaultState);
        addState(mStaEnabledState, mDefaultState);
            addState(mDeviceActiveState, mStaEnabledState);
        addState(mStaDisabledWithScanState, mDefaultState);
        addState(mEcmState, mDefaultState);
    // CHECKSTYLE:ON IndentationCheck
 
    boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
    boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
    boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
    boolean isLocationModeActive =
            mSettingsStore.getLocationModeSetting(mContext)
                    == Settings.Secure.LOCATION_MODE_OFF;
 
    log("isAirplaneModeOn = " + isAirplaneModeOn
            + ", isWifiEnabled = " + isWifiEnabled
            + ", isScanningAvailable = " + isScanningAlwaysAvailable
            + ", isLocationModeActive = " + isLocationModeActive);
 
    if (checkScanOnlyModeAvailable()) {
        setInitialState(mStaDisabledWithScanState);
    } else {
        setInitialState(mStaDisabledState);
    }
    ...
}

看checkScanOnlyModeAvailable方法。

private boolean checkScanOnlyModeAvailable() {
    // first check if Location service is disabled, if so return false
    if (mSettingsStore.getLocationModeSetting(mContext)
            == Settings.Secure.LOCATION_MODE_OFF) {
        return false;
    }
    return mSettingsStore.isScanAlwaysAvailable();
}

mSettingsStore是WifiSettingsStore的对象,看其isScanAlwaysAvailable方法。

11 、frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiSettingsStore.java

public synchronized boolean isScanAlwaysAvailable() {
    return !mAirplaneModeOn && mScanAlwaysAvailable;
}

看mScanAlwaysAvailable是什么。

WifiSettingsStore(Context context) {
    mContext = context;
    mAirplaneModeOn = getPersistedAirplaneModeOn();  //位置1
    mPersistWifiState = getPersistedWifiState();     
    mScanAlwaysAvailable = getPersistedScanAlwaysAvailable();  //位置2
}

看getPersistedScanAlwaysAvailable()方法。

private boolean getPersistedScanAlwaysAvailable() {
    return Settings.Global.getInt(mContext.getContentResolver(),
            Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
            0) == 1;
}

可以看到,最终是判断Wifi的状态是不是处于一直可扫描的状态。

由前面的mAirplaneModeOn = getPersistedAirplaneModeOn()再看mAirplaneModeOn的状态是什么。

private boolean getPersistedAirplaneModeOn() {
    return Settings.Global.getInt(mContext.getContentResolver(),
            Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
}

       可以看到,最终是判断手机是不是飞行模式。

       如果手机不是飞行模式并且Wifi的状态是处于一直可扫描的状态,则返回true,那么WifiController状态机的初始状态被设为StaDisabledState状态,即setInitialState(mStaDisabledState)。否则,初始状态被设为StaDisabledWithScanState状态,即setInitialState(mStaDisabledWithScanState)。我们现在是处于初始状态为StaDisabledState的情况。

WifiController状态机:

       由于初始状态是StaDisabledState,状态机会执行从根状态到StaDisabledState的所有enter()方法,StaDisabledState的父状态为DefultState。DefultState没有重写enter()方法,直接看StaDisabledState的enter()方法。

class StaDisabledState extends State {
    private int mDeferredEnableSerialNumber = 0;
    private boolean mHaveDeferredEnable = false;
    private long mDisabledTimestamp;
 
    @Override
    public void enter() {
        mWifiStateMachinePrime.disableWifi();
        // Supplicant can't restart right away, so note the time we switched off
        mDisabledTimestamp = SystemClock.elapsedRealtime();
        mDeferredEnableSerialNumber++;
        mHaveDeferredEnable = false;
        mWifiStateMachine.clearANQPCache();
    }
}

mWifiStateMachinePrime.disableWifi()首先会关掉Wifi,这个就不再往后延展了。

接着初始状态StaDisabledState开始处理消息CMD_SET_AP。

case CMD_SET_AP:
    // first make sure we aren't in airplane mode
    if (mSettingsStore.isAirplaneModeOn()) {
        log("drop softap requests when in airplane mode");
        break;
    }
    if (msg.arg1 == 1) {
        // remember that we were disabled, but pass the command up to start softap
        mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED);
    }
    return NOT_HANDLED;

       mSettingsStore.setWifiSavedState(WifiSettingsStore.WIFI_DISABLED)会记录Wifi已经关闭的状态,这个不再往后延展。由于最后return NOT_HANDLED,所以说明子状态无法处理则转给父状态处理,即DefaultState。

case CMD_SET_AP:
    // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
 
    // first make sure we aren't in airplane mode
    if (mSettingsStore.isAirplaneModeOn()) {
        log("drop softap requests when in airplane mode");
            break;
        }
        if (msg.arg1 == 1) {
            SoftApModeConfiguration config = (SoftApModeConfiguration) msg.obj;
            mWifiStateMachinePrime.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
        } else {
            mWifiStateMachinePrime.stopSoftAPMode();
        }
    break;

12、 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java

/**
* Method to enable soft ap for wifi hotspot.
*
* The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if
* the persisted config is to be used) and the target operating mode (ex,
* {@link WifiManager.IFACE_IP_MODE_TETHERED} {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
*
* @param wifiConfig SoftApModeConfiguration for the hostapd softap
*/
public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
    mHandler.post(() -> {
        startSoftAp(wifiConfig);
    });
}

startSoftAp。

private void startSoftAp(SoftApModeConfiguration softapConfig) {
    Log.d(TAG, "Starting SoftApModeManager");
 
    WifiConfiguration config = softapConfig.getWifiConfiguration();
    if (config != null && config.SSID != null) {
        Log.d(TAG, "Passing config to SoftApManager! " + config);
    } else {
        config = null;
    }
 
    SoftApCallbackImpl callback = new SoftApCallbackImpl();
    ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig);
    callback.setActiveModeManager(manager);
    manager.start();
    mActiveModeManagers.add(manager);
    updateBatteryStatsWifiState(true);
}

mWifiInjector.makeSoftApManager。

13、 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiInjector.java

/**
* Create a SoftApManager.
* @param listener listener for SoftApManager
* @param config SoftApModeConfiguration object holding the config and mode
* @return an instance of SoftApManager
*/
public SoftApManager makeSoftApManager(@NonNull WifiManager.SoftApCallback callback,
                                          @NonNull SoftApModeConfiguration config) {
    return new SoftApManager(mContext, mWifiStateMachineHandlerThread.getLooper(),
            mFrameworkFacade, mWifiNative, mCountryCode.getCountryCode(), callback,
            mWifiApConfigStore, config, mWifiMetrics);
}

manager.start()。

14 frameworks/opt/net/wifi/service/java/com/android/server/wifi/ActiveModeManager.java

/**
* Method used to start the Manager for a given Wifi operational mode.
*/
void start();

start()。

15、 frameworks/opt/net/wifi/service/java/com/android/server/wifi/SoftApManager.java

/**
* Start soft AP with the supplied config.
*/
public void start() {
    mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
}

SoftApStateMachine.CMD_START。

SoftApStateMachine是SoftApManager的内部类。

@Override
public boolean processMessage(Message message) {
    switch (message.what) {
        case CMD_START:
            mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
                    mWifiNativeInterfaceCallback);
            if (TextUtils.isEmpty(mApInterfaceName)) {
                Log.e(TAG, "setup failure when creating ap interface.");
                updateApState(WifiManager.WIFI_AP_STATE_FAILED,
                        WifiManager.WIFI_AP_STATE_DISABLED,
                        WifiManager.SAP_START_FAILURE_GENERAL);
                mWifiMetrics.incrementSoftApStartResult(
                        false, WifiManager.SAP_START_FAILURE_GENERAL);
                break;
            }
            updateApState(WifiManager.WIFI_AP_STATE_ENABLING,
            WifiManager.WIFI_AP_STATE_DISABLED, 0);
            int result = startSoftAp((WifiConfiguration) message.obj);
            if (result != SUCCESS) {
                int failureReason = WifiManager.SAP_START_FAILURE_GENERAL;
                if (result == ERROR_NO_CHANNEL) {
                    failureReason = WifiManager.SAP_START_FAILURE_NO_CHANNEL;
                }
                updateApState(WifiManager.WIFI_AP_STATE_FAILED,
                        WifiManager.WIFI_AP_STATE_ENABLING,
                        failureReason);
                stopSoftAp();
                mWifiMetrics.incrementSoftApStartResult(false, failureReason);
                break;
            }
            transitionTo(mStartedState);
            break;
            default:
                // Ignore all other commands.
                break;
            }
 
            return HANDLED;
    }
}

startSoftAp。

/**
* Start a soft AP instance with the given configuration.
* @param config AP configuration
* @return integer result code
*/
private int startSoftAp(WifiConfiguration config) {
    if (config == null || config.SSID == null) {
        Log.e(TAG, "Unable to start soft AP without valid configuration");
        return ERROR_GENERIC;
    }
 
    // Make a copy of configuration for updating AP band and channel.
    WifiConfiguration localConfig = new WifiConfiguration(config);
 
    int result = ApConfigUtil.updateApChannelConfig(
            mWifiNative, mCountryCode,
            mWifiApConfigStore.getAllowed2GChannel(), localConfig);
 
    if (result != SUCCESS) {
        Log.e(TAG, "Failed to update AP band and channel");
        return result;
    }
 
    // Setup country code if it is provided.
    if (mCountryCode != null) {
        // Country code is mandatory for 5GHz band, return an error if failed to set
        // country code when AP is configured for 5GHz band.
        if (!mWifiNative.setCountryCodeHal(
                mApInterfaceName, mCountryCode.toUpperCase(Locale.ROOT))
                && config.apBand == WifiConfiguration.AP_BAND_5GHZ) {
            Log.e(TAG, "Failed to set country code, required for setting up "
                    + "soft ap in 5GHz");
            return ERROR_GENERIC;
        }
    }
    if (localConfig.hiddenSSID) {
        Log.d(TAG, "SoftAP is a hidden network");
    }
    if (!mWifiNative.startSoftAp(mApInterfaceName, localConfig, mSoftApListener)) {
        Log.e(TAG, "Soft AP start failed");
        return ERROR_GENERIC;
    }
    Log.d(TAG, "Soft AP is started");
 
    return SUCCESS;
}

mWifiNative.startSoftAp。

16 、frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

/**
* Start Soft AP operation using the provided configuration.
*
* @param ifaceName Name of the interface.
* @param config Configuration to use for the soft ap created.
* @param listener Callback for AP events.
* @return true on success, false otherwise.
*/
public boolean startSoftAp(
        @NonNull String ifaceName, WifiConfiguration config, SoftApListener listener) {
    if (!mWificondControl.startHostapd(ifaceName, listener)) {
        Log.e(TAG, "Failed to start hostapd");
        mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
        return false;
    }
    if (!waitForHostapdConnection()) {
        Log.e(TAG, "Failed to establish connection to hostapd");
        mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
        return false;
    }
    if (!mHostapdHal.registerDeathHandler(new HostapdDeathHandlerInternal())) {
        Log.e(TAG, "Failed to register hostapd death handler");
        mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
        return false;
    }
    if (!mHostapdHal.addAccessPoint(ifaceName, config)) {
        Log.e(TAG, "Failed to add acccess point");
        mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
        return false;
    }
    return true;
}

做了这些操作:

  • mWificondControl.startHostapd
  • waitForHostapdConnection
  • mHostapdHal.registerDeathHandler
  • mHostapdHal.addAccessPoint

就以mWificondControl.startHostapd为主线进行分析。

17、 frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java

/**
* Start hostapd
* TODO(b/71513606): Move this to a global operation.
*
* @param ifaceName Name of the interface.
* @param listener Callback for AP events.
* @return true on success, false otherwise.
*/
public boolean startHostapd(@NonNull String ifaceName,
                              SoftApListener listener) {
    IApInterface iface = getApInterface(ifaceName);
    if (iface == null) {
        Log.e(TAG, "No valid ap interface handler");
        return false;
    }
    try {
        IApInterfaceEventCallback  callback = new ApInterfaceEventCallback(listener);
        mApInterfaceListeners.put(ifaceName, callback);
        boolean success = iface.startHostapd(callback);
        if (!success) {
            Log.e(TAG, "Failed to start hostapd.");
            return false;
        }
    } catch (RemoteException e) {
        Log.e(TAG, "Exception in starting soft AP: " + e);
        return false;
    }
    return true;
}

看iface.startHostapd,走到Native层。

18 、system/connectivity/wificond/aidl/android/net/wifi/IApInterface.aidl

// Start up an instance of hostapd associated with this interface.
//
// @param callback Object to add a set of event callbacks.
// @return true on success.
boolean startHostapd(IApInterfaceEventCallback callback);

19 、system/connectivity/wificond/ap_interface_binder.h

binder::Status startHostapd(
    const sp<net::wifi::IApInterfaceEventCallback>& callback,
     bool* out_success) override;

20 、system/connectivity/wificond/ap_interface_binder.cpp

startHostapd。

binder::Status ApInterfaceBinder::startHostapd(
    const sp<IApInterfaceEventCallback>& callback, bool* out_success) {
    *out_success = false;
    if (!impl_) {
        LOG(WARNING) << "Cannot start hostapd on dead ApInterface.";
        return binder::Status::ok();
    }
    *out_success = impl_->StartHostapd();
    if (*out_success) {
        ap_interface_event_callback_ = callback;
    }
    return binder::Status::ok();
}
impl_->StartHostapd()。

21 、system/connectivity/wificond/ap_interface_impl.h

#ifndef WIFICOND_AP_INTERFACE_IMPL_H_
#define WIFICOND_AP_INTERFACE_IMPL_H_
 
#include <string>
#include <vector>
 
#include <android-base/macros.h>
#include <wifi_system/hostapd_manager.h>
#include <wifi_system/interface_tool.h>
 
#include "wificond/net/netlink_manager.h"
 
#include "android/net/wifi/IApInterface.h"
 
namespace android {
namespace wificond {
 
class ApInterfaceBinder;
class NetlinkUtils;
 
// Holds the guts of how we control network interfaces capable of exposing an AP
// via hostapd.  Because remote processes may hold on to the corresponding
// binder object past the lifetime of the local object, we are forced to
// keep this object separate from the binder representation of itself.
class ApInterfaceImpl {
 public:
  ApInterfaceImpl(const std::string& interface_name,
                  uint32_t interface_index,
                  NetlinkUtils* netlink_utils,
                  wifi_system::InterfaceTool* if_tool,
                  wifi_system::HostapdManager* hostapd_manager);
  ~ApInterfaceImpl();
 
  // Get a pointer to the binder representing this ApInterfaceImpl.
  android::sp<android::net::wifi::IApInterface> GetBinder() const;
 
  bool StartHostapd();
  bool StopHostapd();
  std::string GetInterfaceName() { return interface_name_; }
  int GetNumberOfAssociatedStations() const;
  void Dump(std::stringstream* ss) const;
 
 private:
  const std::string interface_name_;
  const uint32_t interface_index_;
  NetlinkUtils* const netlink_utils_;
  wifi_system::InterfaceTool* const if_tool_;
  wifi_system::HostapdManager* const hostapd_manager_;
  const android::sp<ApInterfaceBinder> binder_;
 
  // Number of associated stations.
  int number_of_associated_stations_;
 
  void OnStationEvent(StationEvent event,
                      const std::vector<uint8_t>& mac_address);
 
  void OnChannelSwitchEvent(uint32_t frequency, ChannelBandwidth bandwidth);
 
  DISALLOW_COPY_AND_ASSIGN(ApInterfaceImpl);
};
 
}  // namespace wificond
}  // namespace android
 
#endif  // WIFICOND_AP_INTERFACE_IMPL_H_

StartHostapd()。

22、 system/connectivity/wificond/ap_interface_impl.cpp

bool ApInterfaceImpl::StartHostapd() {
    return hostapd_manager_->StartHostapd();
}

 
————————————————
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值