如果你也是年輕的程序員,關注我一起學習探討
Android9.0中對熱點做了較大改動,將熱點很大程度從Wifi中剝離出來了。
下面我們看一下熱點是怎么開啟的。
首先是在WifiTetherSettings中,調用startTether()函數,可以看到startTether函數中主要是調用了WifiTetherSwitchBarController.java中的startTether()函數。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSettings.java#174
private void startTether() {
mRestartWifiApAfterConfigChange = false;
mSwitchBarController.startTether();
}
然后我們看WifiTetherSwitchBarController里的startTether函數,WifiTetherSwitchBarController是用來控制開關欄切換的,可以看到他調用了ConnectivityManager的startTethering函數。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/packages/apps/Settings/src/com/android/settings/wifi/tether/WifiTetherSwitchBarController.java#107
void startTether() {
mSwitchBar.setEnabled(false);
mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
}
然后在這里調用了ConnectivityService的startTethering函數。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/java/android/net/ConnectivityManager.java#2261
public void startTethering(int type, boolean showProvisioningUi,
final OnStartTetheringCallback callback, Handler handler) {
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);
}
}
在ConnectivityService中,會跳到Tethering.java的startTethering函數。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/ConnectivityService.java#3232
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);
}
在Tethering.java中,函數的調用順序如下:startTethering—>enableTetheringInternal—>setWifiTethering。在setWifiTethering中,調用了WifiManager的startSoftAp函數。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/services/core/java/com/android/server/connectivity/Tethering.java#368
368 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);
}
}
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;
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;
}
在這里調用了WifiServiceImpl.java的startSoftAp函數。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/base/wifi/java/android/net/wifi/WifiManager.java#1909
public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) {
try {
return mService.startSoftAp(wifiConfig);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
在這里調用了startSoftApInternal函數,然后向WifiController的狀態機發送了CMD_SET_AP消息。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java#1004
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);
}
}
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;
}
在這里,處理結果是調用WifiStateMachinePrime的enterSoftAPMode方法。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java#593
class DefaultState extends State {
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;
在WifiStateMachinePrime中,創建了SoftApManager對象,並且調用了start方法。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachinePrime.java#549
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();
ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig);
callback.setActiveModeManager(manager);
manager.start();
mActiveModeManagers.add(manager);
updateBatteryStatsWifiState(true);
}
在這里,StateMachine發送了消息CMD_START,然后由IdleState 處理,這里主要的處理結果就是調用startSoftAp方法。在startSoftAp里,調用了WifiNative.java的startSoftAp方法。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/SoftApManager.java#142
public void start() {
mStateMachine.sendMessage(SoftApStateMachine.CMD_START, mApConfig);
}
private class IdleState extends State {
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;
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;
}
在這里,主要是調用WificondControl.java的startHostapd方法。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java#1250
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;
}
在這里可以看到創建了IApInterface 對象,然后調用了他的startHostapd方法。而IApInterface 是由ap_interface_impl.cpp實現的。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WificondControl.java#787
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;
}
在這里又調用了hostapd_manager的StartHostapd函數。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/system/connectivity/wificond/ap_interface_impl.cpp#86
bool ApInterfaceImpl::StartHostapd() {
return hostapd_manager_->StartHostapd();
}
然后在hostapd_manager.cpp里調用了StartHostapd方法。
源碼路徑:
http://androidxref.com/9.0.0_r3/xref/frameworks/opt/net/wifi/libwifi_system/hostapd_manager.cpp#26
bool HostapdManager::StartHostapd() {
if (property_set("ctl.start", kHostapdServiceName) != 0) {
LOG(ERROR) << "Failed to start SoftAP";
return false;
LOG(DEBUG) << "SoftAP started successfully";
return true;
}
再往后就是底層C的代碼了,不是特別看得懂。然后返回success的話,熱點就成功打開了,狀態也變為started。