softap的入口在ConnectivityManager.java中,作为连接的一部分。老版本Android的入口在WifiManager.java中。应用启动softap时,调用ConnectivityManager.startTethering()开始。
@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);
}
}
参数type有三个类型:
ConnectivityManager.TETHERING_WIFI
ConnectivityManager.TETHERING_USB
ConnectivityManager.TETHERING_BLUETOOTH
我们现在关注的TETHERING_WIFI。进入到ConnectivityService.java中:
@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);
}
mTethering是Tethering类的实例。mTethering.startTethering的将调用enableTetheringInternal()方法。
private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
int result;
switch (type) {
case TETHERING_WIFI:
result = setWifiTethering(enable);
sendTetherResult(receiver, result);
break;
case TETHERING_USB:
result = setUsbTethering(enable);
sendTetherResult(receiver, result);
break;
case TETHERING_BLUETOOTH:
setBluetoothTethering(enable, receiver);
break;
default:
Log.w(TAG, "Invalid tether type.");
sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
}
}
private int setWifiTethering(final boolean enable) {
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mPublicSync) {
final WifiManager mgr = getWifiManager();
if (mgr == null) {
mLog.e("setWifiTethering: failed to get WifiManager!");
return TETHER_ERROR_SERVICE_UNAVAIL;
}
if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
(!enable && mgr.stopSoftAp())) {
mWifiTetherRequested = enable;
return TETHER_ERROR_NO_ERROR;
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
return TETHER_ERROR_MASTER_ERROR;
}
对于softap,在setWifiTethering()方法中,将调用WifiManager.startSoftAp(null),一切回到从前。
直接进入WifiServiceImpl.java中查看。
@WifiServiceImpl.java
public boolean startSoftAp(WifiConfiguration wifiConfig) {
return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
}
这里的wifiConfig参数为null。startSoftApInternal()方法实现为:
@WifiServiceImpl.java
private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
mLog.trace("startSoftApInternal uid=% mode=%")
.c(Binder.getCallingUid()).c(mode).flush();
if (wifiConfig == null && TextUtils.isEmpty(mCountryCode.getCountryCode())) {
Log.d(TAG, "Starting softap without country code. Fallback to 2G band");
wifiConfig = new WifiConfiguration(mWifiApConfigStore.getApConfiguration());
wifiConfig.apBand = WifiConfiguration.AP_BAND_2GHZ;
}
setDualSapMode(wifiConfig);
if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) {
SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
Log.i(TAG, "Starting softap 2 apChannel=" + wifiConfig.apChannel);
mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
return true;
}
}
上面的代码,首先会尝试从WifiApConfigStore中获取已经保存的ap配置信息。这个信息是通过WifiManager.setWifiApConfiguration()方法写入的。如果WifiApConfigStore获取不到,null也可以继续往下传递。接下来有WifiController出来CMD_SET_AP消息。
CMD_SET_AP消息会在WifiController的父类状态DefaultState中处理。处理方法如下:
@WifiController.java
case CMD_SET_AP:
// note: CMD_SET_AP is handled/dropped in ECM mode - will not start here
// If request is to start dual sap, turn off sta.
if (msg.arg1 == 1 && mWifiApConfigStore.getDualSapStatus()) {
mActiveModeWarden.disableWifi();
transitionTo(mStaDisabledState);
}
if (msg.arg1 == 1) {
SoftApModeConfiguration config = (SoftApModeConfiguration) msg.obj;
mActiveModeWarden.enterSoftAPMode((SoftApModeConfiguration) msg.obj);
} else {
mActiveModeWarden.stopSoftAPMode(msg.arg2);
}
break;
转入WIFI模式管理类进一步操作:
@ActiveModeWarden.java
public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) {
mHandler.post(() -> {
startSoftAp(wifiConfig);
});
}
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(softapConfig.getTargetMode());
ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig);
callback.setActiveModeManager(manager);
manager.start();
mActiveModeManagers.add(manager);
updateBatteryStatsWifiState(true);
}
SoftApCallbackImpl类中将调用WifiManager.SoftApCallbackImpl()注册的回调方法,通知到应用程序。makeSoftApManager构造一个SoftApManager对象。Client, softap都有一个父类为ActiveModeManager的状态管理类。makeSoftApManager()方法中传入了apconfig, 回调防暑等必要信息。
调用SoftApManager的start方法。
public void start() {
mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
}
向mStateMachine状态机发送CMD_START信息。
在SoftApManager.java中有SoftApStateMachine状态机。只有两种状态:
@SoftApManager.java
SoftApStateMachine(Looper looper) {
super(TAG, looper);
addState(mIdleState);
addState(mStartedState);
setInitialState(mIdleState);
start();
}
CMD_START在IdleState中处理,首先会启动hostapd进程。
mApInterfaceName = mWifiNative.setupInterfaceForSoftApMode(
mWifiNativeInterfaceCallback);
最后将调用startSoftAp()。
@SoftApManager.java
private int startSoftAp(WifiConfiguration config) {
//设置国家码
mWifiNative.setCountryCodeHal(
mApInterfaceName, mCountryCode.toUpperCase(Locale.ROOT));
// 是否支持5G
if (config.apBand == WifiConfiguration.AP_BAND_5GHZ
&& !mWifiNative.is5GhzBandSupported()) {
mSoftApStartFailureDesc = WifiManager.WIFI_AP_FAILURE_DESC_NO_5GHZ_SUPPORT;
Log.e(TAG, "Failed to start soft AP as 5Ghz band not supported");
return ERROR_NO_CHANNEL;
} else {
mSoftApStartFailureDesc = "";
}
// Make a copy of configuration for updating AP band and channel.
WifiConfiguration localConfig = new WifiConfiguration(config);
// 如果apchannel,根据配置文件config_wifi_framework_sap_2G_channel_list,随机查找一个信道
int result = ApConfigUtil.updateApChannelConfig(
mWifiNative, mCountryCode,
mWifiApConfigStore.getAllowed2GChannel(), localConfig);
// 开启SoftAp
mWifiNative.startSoftAp(mApInterfaceName, localConfig, mSoftApListener);
mStartTimestamp = SystemClock.elapsedRealtime();
}
上面函数,在通过检查国家码,是否支持5G信道后,来判断配置是否正确。如果apchannel=0,还会从xml设置的信道中,随机选择一个信道作为参数。最后调用WifiNative.startSoftAp().
public boolean startSoftAp(
@NonNull String ifaceName, WifiConfiguration config, SoftApListener listener) {
if (!mWificondControl.registerApListener(ifaceName, listener)) {
Log.e(TAG, "Failed to register ap listener");
return false;
}
if (mHostapdHal.isVendorHostapdHal()) {
if (!mHostapdHal.addVendorAccessPoint(ifaceName, config, listener)) {
Log.e(TAG, "Failed to add Vendor acccess point");
mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
return false;
}
}
}