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