@Override publicbooleanstartSoftAp(WifiConfiguration wifiConfig) { // NETWORK_STACK is a signature only permission. enforceNetworkStackPermission(); // If we're in crypt debounce, ignore any wifi state change APIs. if (mFrameworkFacade.inStorageManagerCryptKeeperBounce()) { returnfalse; }
synchronized (mLocalOnlyHotspotRequests) { // If a tethering request comes in while we have an existing tethering session, return // error. if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_TETHERED)) { mLog.err("Tethering is already active.").flush(); returnfalse; } // 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 (!isConcurrentLohsAndTetheringSupported() && !mLocalOnlyHotspotRequests.isEmpty()) { stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); } return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED); } }
这个函数首先会判断是否有本地热点(Local Only Hotspot, 就是无法使用网络连接的热点, 只用于两个设备之间通讯), 如果有的话, 就开启一个非共享的热点, 否则开启一个有共享的热点. 这里只看下有共享的流程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
privatebooleanstartSoftApInternal(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)) { SoftApModeConfigurationsoftApConfig=newSoftApModeConfiguration(mode, wifiConfig); mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig); returntrue; } Slog.e(TAG, "Invalid WifiConfiguration"); returnfalse; }
@Override publicvoidenter() { mActiveModeWarden.disableWifi(); // Supplicant can't restart right away, so note the time we switched off mDisabledTimestamp = SystemClock.elapsedRealtime(); mDeferredEnableSerialNumber++; mHaveDeferredEnable = false; } @Override publicbooleanprocessMessage(Message msg) { switch (msg.what) { case CMD_WIFI_TOGGLED: if (mSettingsStore.isWifiToggleEnabled()) { if (doDeferEnable(msg)) { if (mHaveDeferredEnable) { // have 2 toggles now, inc serial number and ignore both mDeferredEnableSerialNumber++; } mHaveDeferredEnable = !mHaveDeferredEnable; break; } transitionTo(mStaEnabledState); } elseif (checkScanOnlyModeAvailable()) { // only go to scan mode if we aren't in airplane mode if (mSettingsStore.isAirplaneModeOn()) { transitionTo(mStaDisabledWithScanState); } } break; .... case CMD_SET_AP: 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; .... default: return NOT_HANDLED; } return HANDLED; } .... }
classDefaultStateextendsState { @Override publicbooleanprocessMessage(Message msg) { switch (msg.what) { .... case CMD_SET_AP: // note: CMD_SET_AP is handled/dropped in ECM mode - will not start here if (msg.arg1 == 1) { SoftApModeConfigurationconfig= (SoftApModeConfiguration) msg.obj; mActiveModeWarden.enterSoftAPMode((SoftApModeConfiguration) msg.obj); } else { mActiveModeWarden.stopSoftAPMode(msg.arg2); } break; case CMD_AIRPLANE_TOGGLED: if (mSettingsStore.isAirplaneModeOn()) { log("Airplane mode toggled, shutdown all modes"); mActiveModeWarden.shutdownWifi(); transitionTo(mStaDisabledState); } else { log("Airplane mode disabled, determine next state"); if (mSettingsStore.isWifiToggleEnabled()) { transitionTo(mStaEnabledState); } elseif (checkScanOnlyModeAvailable()) { transitionTo(mStaDisabledWithScanState); } // wifi should remain disabled, do not need to transition } break; case CMD_EMERGENCY_CALL_STATE_CHANGED: case CMD_EMERGENCY_MODE_CHANGED: if (msg.arg1 == 1) { transitionTo(mEcmState); } break; case CMD_AP_STOPPED: log("SoftAp mode disabled, determine next state"); if (mSettingsStore.isWifiToggleEnabled()) { transitionTo(mStaEnabledState); } elseif (checkScanOnlyModeAvailable()) { transitionTo(mStaDisabledWithScanState); } // wifi should remain disabled, do not need to transition break; default: thrownewRuntimeException("WifiController.handleMessage " + msg.what); } return HANDLED; }
public String setupInterfaceForSoftApMode(@NonNull InterfaceCallback interfaceCallback) { synchronized (mLock) { if (!startHal()) { Log.e(TAG, "Failed to start Hal"); mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal(); returnnull; } if (!startHostapd()) { Log.e(TAG, "Failed to start hostapd"); mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd(); returnnull; } Ifaceiface= mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP); if (iface == null) { Log.e(TAG, "Failed to allocate new AP iface"); returnnull; } iface.externalListener = interfaceCallback; iface.name = createApIface(iface); if (TextUtils.isEmpty(iface.name)) { Log.e(TAG, "Failed to create AP iface in vendor HAL"); mIfaceMgr.removeIface(iface.id); mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal(); returnnull; } // 调用HAL接口创建AP网口 if (mWificondControl.setupInterfaceForSoftApMode(iface.name) == null) { Log.e(TAG, "Failed to setup iface in wificond on " + iface); teardownInterface(iface.name); mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToWificond(); returnnull; } iface.networkObserver = newNetworkObserverInternal(iface.id); if (!registerNetworkObserver(iface.networkObserver)) { Log.e(TAG, "Failed to register network observer on " + iface); teardownInterface(iface.name); returnnull; } // 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);
// WifiCondControl public IApInterface setupInterfaceForSoftApMode(@NonNull String ifaceName) { Log.d(TAG, "Setting up interface for soft ap mode"); if (!retrieveWificondAndRegisterForDeath()) { returnnull; }
IApInterfaceapInterface=null; try { apInterface = mWificond.createApInterface(ifaceName); } catch (RemoteException e1) { Log.e(TAG, "Failed to get IApInterface due to remote exception"); returnnull; } .... Binder.allowBlocking(apInterface.asBinder());
// SoftApManager privatevoidonUpChanged(boolean isUp) { if (isUp == mIfaceIsUp) { return; // no change } mIfaceIsUp = isUp; if (isUp) { Log.d(TAG, "SoftAp is ready for use"); updateApState(WifiManager.WIFI_AP_STATE_ENABLED, WifiManager.WIFI_AP_STATE_ENABLING, 0); mWifiMetrics.incrementSoftApStartResult(true, 0); if (mCallback != null) { mCallback.onNumClientsChanged(mNumAssociatedStations); } } else { // the interface was up, but goes down sendMessage(CMD_INTERFACE_DOWN); } mWifiMetrics.addSoftApUpChangedEvent(isUp, mMode); }
privatevoidupdateApState(int newState, int currentState, int reason) { mCallback.onStateChanged(newState, reason);
//send the AP state change broadcast finalIntentintent=newIntent(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(WifiManager.EXTRA_WIFI_AP_STATE, newState); intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE, currentState); if (newState == WifiManager.WIFI_AP_STATE_FAILED) { //only set reason number when softAP start failed intent.putExtra(WifiManager.EXTRA_WIFI_AP_FAILURE_REASON, reason); }
synchronized (Tethering.this.mPublicSync) { switch (curState) { case WifiManager.WIFI_AP_STATE_ENABLING: // We can see this state on the way to both enabled and failure states. break; case WifiManager.WIFI_AP_STATE_ENABLED: enableWifiIpServingLocked(ifname, ipmode); break; case WifiManager.WIFI_AP_STATE_DISABLED: case WifiManager.WIFI_AP_STATE_DISABLING: case WifiManager.WIFI_AP_STATE_FAILED: default: disableWifiIpServingLocked(ifname, curState); break; } } }
privatevoidmaybeTrackNewInterfaceLocked(final String iface, int interfaceType) { // If we have already started a TISM for this interface, skip. if (mTetherStates.containsKey(iface)) { mLog.log("active iface (" + iface + ") reported as added, ignoring"); return; }
if (DBG) Log.d(TAG, "Tethered " + mIfaceName); sendInterfaceState(STATE_TETHERED); }
...
@Override publicbooleanprocessMessage(Message message) { if (super.processMessage(message)) returntrue;
logMessage(this, message.what); switch (message.what) { case CMD_TETHER_REQUESTED: mLog.e("CMD_TETHER_REQUESTED while already tethering."); break; // 上游网络连接可用 case CMD_TETHER_CONNECTION_CHANGED: finalInterfaceSetnewUpstreamIfaceSet= (InterfaceSet) message.obj; if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) { if (VDBG) Log.d(TAG, "Connection changed noop - dropping"); break; }
if (newUpstreamIfaceSet == null) { cleanupUpstream(); break; }
for (String removed : upstreamInterfacesRemoved(newUpstreamIfaceSet)) { cleanupUpstreamInterface(removed); }
final Set<String> added = upstreamInterfacesAdd(newUpstreamIfaceSet); // This makes the call to cleanupUpstream() in the error // path for any interface neatly cleanup all the interfaces. mUpstreamIfaceSet = newUpstreamIfaceSet;