关于DHCP协议和对应的包,网上一搜很多,这里就不记录了,大致看下代码流程,代码选取 Android 13 的。
Android 13 ClientModeImpl 类里面的状态机如下:
865 addState(mConnectableState); {
866 addState(mConnectingOrConnectedState, mConnectableState); {
867 addState(mL2ConnectingState, mConnectingOrConnectedState);
868 addState(mL2ConnectedState, mConnectingOrConnectedState); {
869 addState(mL3ProvisioningState, mL2ConnectedState);
870 addState(mL3ConnectedState, mL2ConnectedState);
871 addState(mRoamingState, mL2ConnectedState);
872 }
873 }
874 addState(mDisconnectedState, mConnectableState);
875 }
876
877 setInitialState(mDisconnectedState);
状态机层次关系如下,所有的父状态是 mConnectableState:
那什么时候回执行到 ClientModeImpl 类里面呢?这时候我们要回看下之前写的文章,开启 Wi-Fi 流程
这里面提到,打开Wi-Fi,底层初始化完成后,在 /packages/modules/Wifi/service/java/com/android/server/wifi/ConcreteClientModeManager.java里面的ConnectModeState 状态机中,去创建 ClientMode,其实我们只要知道ConcreteClientModeManager里面两种模式即可:Client Mode 和 Scan Only Mode,对应的类就是ClientModeImpl 和 ScanOnlyModeImpl,在回看下创建 ClientMode 代码:
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/
ConcreteClientModeManager.java#makeClientModeImpl
1031 private class ConnectModeState extends State {
1032 @Override
1033 public void enter() {
1034 Log.d(getTag(), "entering ConnectModeState, starting ClientModeImpl");
1035 if (mClientInterfaceName == null) {
1036 Log.e(getTag(), "Supposed to start ClientModeImpl, but iface is null!");
1037 } else {
1038 if (mClientModeImpl != null) {
1039 Log.e(getTag(), "ConnectModeState.enter(): mClientModeImpl is already "
1040 + "instantiated?!");
1041 }
1042 mClientModeImpl = mWifiInjector.makeClientModeImpl( ---> 这个就是创建 Client Mode的地方
1043 mClientInterfaceName, ConcreteClientModeManager.this,
1044 mVerboseLoggingEnabled);
1045 mClientModeImpl.setShouldReduceNetworkScore(mShouldReduceNetworkScore);
1046 }
1047 if (mConnectRoleChangeInfoToSetOnTransition == null
1048 || !(mConnectRoleChangeInfoToSetOnTransition.role
1049 instanceof ClientConnectivityRole)) {
1050 Log.wtf(TAG, "Unexpected mConnectRoleChangeInfoToSetOnTransition: "
1051 + mConnectRoleChangeInfoToSetOnTransition);
1052 // Should never happen, but fallback to primary to avoid a crash.
1053 mConnectRoleChangeInfoToSetOnTransition =
1054 new RoleChangeInfo(ROLE_CLIENT_PRIMARY);
1055 }
1056
1057 // Could be any one of possible connect mode roles.
1058 setRoleInternalAndInvokeCallback(mConnectRoleChangeInfoToSetOnTransition);
1059 updateConnectModeState(mConnectRoleChangeInfoToSetOnTransition.role,
1060 WIFI_STATE_ENABLED, WIFI_STATE_ENABLING);
1061 }
Ok,再回到 ClientModeImpl 类里面,父状态ConnectableState :
class ConnectableState extends State {
@Override
public void enter() {
Log.d(getTag(), "entering ConnectableState: ifaceName = " + mInterfaceName);
setSuspendOptimizationsNative(SUSPEND_DUE_TO_HIGH_PERF, true);
mWifiStateTracker.updateState(mInterfaceName, WifiStateTracker.INVALID);
mIpClientCallbacks = new IpClientCallbacksImpl();
Log.d(getTag(), "Start makeIpClient ifaceName = " + mInterfaceName);
mFacade.makeIpClient(mContext, mInterfaceName, mIpClientCallbacks); ---> 创建 IpClient,并注册一个mIpClientCallbacks
mIpClientCallbacks.awaitCreation(); ---> 2s
}
看下 makeIpClient 流程:
// packages/modules/Wifi/service/java/com/android/server/wifi/FrameworkFacade.java#220
public void makeIpClient(Context context, String iface, IpClientCallbacks callback) {
IpClientUtil.makeIpClient(context, iface, callback);
}
// packages/modules/NetworkStack/common/networkstackclient/src/android/net/ip/IpClientUtil.java#79
public static void makeIpClient(Context context, String ifName, IpClientCallbacks callback) {
ModuleNetworkStackClient.getInstance(context).makeIpClient(ifName, new IpClientCallbacksProxy(callback)); ---> callback部分代码未贴出,这里我们先关心makeIpClient流程
ModuleNetworkStackClient父类NetworkStackClientBase中 makeIpClient:
69 public void makeIpClient(String ifName, IIpClientCallbacks cb) {
70 requestConnector(connector -> {
71 try {
72 connector.makeIpClient(ifName, cb); ---> 实现是 NetworkStackConnector,所以看这里的代码
73 } catch (RemoteException e) {
74 throw new IllegalStateException("Could not create IpClient", e);
75 }
76 });
77 }
}
// packages/modules/NetworkStack/src/com/android/server/NetworkStackService.java#makeIpClient
376 @Override
377 public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException {
378 mPermChecker.enforceNetworkStackCallingPermission();
379 updateNetworkStackAidlVersion(cb.getInterfaceVersion(), cb.getInterfaceHash());
380 final IpClient ipClient = mDeps.makeIpClient(
381 mContext, ifName, cb, mObserverRegistry, this);
382
383 synchronized (mIpClients) {
384 final Iterator<WeakReference<IpClient>> it = mIpClients.iterator();
385 while (it.hasNext()) {
386 final IpClient ipc = it.next().get();
387 if (ipc == null) {
388 it.remove();
389 }
390 }
391 mIpClients.add(new WeakReference<>(ipClient));
392 }
393 // 创建成功后就回掉这个方法:
394 cb.onIpClientCreated(ipClient.makeConnector());
395 }
onIpClientCreated 回调到 ClientMode里面 packages/modules/Wifi/service/java/com/android/server/wifi/
ClientModeImpl.java#onIpClientCreated
993 class IpClientCallbacksImpl extends IpClientCallbacks {
994 private final ConditionVariable mWaitForCreationCv = new ConditionVariable(false);
995 private final ConditionVariable mWaitForStopCv = new ConditionVariable(false);
996
997 @Override
998 public void onIpClientCreated(IIpClient ipClient) {
999 // IpClient may take a very long time (many minutes) to start at boot time. But after
1000 // that IpClient should start pretty quickly (a few seconds).
1001 // Blocking wait for 5 seconds first (for when the wait is short)
1002 // If IpClient is still not ready after blocking wait, async wait (for when wait is
1003 // long). Will drop all connection requests until IpClient is ready. Other requests
1004 // will still be processed.
1005 sendMessageAtFrontOfQueue(CMD_CONNECTABLE_STATE_SETUP, ---> 发送消息
1006 new IpClientManager(ipClient, getName()));
1007 mWaitForCreationCv.open();
1008 }
我们上面刚看到,此时的状态机是在ConnectModeState,那看下处理这个消息的地方:CMD_CONNECTABLE_STATE_SETUP
3915 case CMD_CONNECTABLE_STATE_SETUP:
3916 if (mIpClient != null) {
3917 loge("Setup connectable state again when IpClient is ready?");
3918 } else {
3919 IpClientManager ipClientManager = (IpClientManager) message.obj;
3920 continueEnterSetup(ipClientManager); ---> 看这个
3921 }
3922 break;
3865 private void continueEnterSetup(IpClientManager ipClientManager) {
3866 mIpClient = ipClientManager;
3867 setupClientMode(); ---》 做一些初始化工作,具体的可以看下代码
3868
3869 IntentFilter filter = new IntentFilter();
3870 filter.addAction(Intent.ACTION_SCREEN_ON);
3871 filter.addAction(Intent.ACTION_SCREEN_OFF);
3872 if (!mIsScreenStateChangeReceiverRegistered) {
3873 mContext.registerReceiver(mScreenStateChangeReceiver, filter);
3874 mIsScreenStateChangeReceiverRegistered = true;
3875 }
3876 // Learn the initial state of whether the screen is on.
3877 // We update this field when we receive broadcasts from the system.
3878 handleScreenStateChanged(mContext.getSystemService(PowerManager.class).isInteractive());
3879
3880 if (!mWifiNative.removeAllNetworks(mInterfaceName)) {
3881 loge("Failed to remove networks on entering connect mode");
3882 }
3883 mWifiInfo.reset();
3884 mWifiInfo.setSupplicantState(SupplicantState.DISCONNECTED);
3885
3886 sendNetworkChangeBroadcast(DetailedState.DISCONNECTED);
3887
3888 // Inform metrics that Wifi is Enabled (but not yet connected)
3889 mWifiMetrics.setWifiState(mInterfaceName, WifiMetricsProto.WifiLog.WIFI_DISCONNECTED);
3890 mWifiMetrics.logStaEvent(mInterfaceName, StaEvent.TYPE_WIFI_ENABLED);
3891 mWifiScoreCard.noteSupplicantStateChanged(mWifiInfo);
3892 }
OK,接下来就是连接某个界面上的AP,ClientModeImpl类里面的流程还是差不多的,调用 connectNetwork —> 发送 CMD_CONNECT_NETWORK消息 —> connectToUserSelectNetwork —> startConnectToNetwork —> 发送CMD_START_CONNECT —> connectToNetwork(注意看下这个方法,因为这里把状态切到L2ConnectingState,而L2ConnectingState的父状态是ConnectingOrConnectedState,接下来我们会在这个状态里面处理连接成功上报的事件)。那我们直接看连接后分配Ip的相关代码流程,当收到 WifiMonitor.NETWORK_CONNECTION_EVENT 事件表示连接成功(即wpa已经CTRL-EVENT-CONNECTED),父状态处理 ConnectingOrConnectedState里面处理,主要是注意下这个 mWifiConfigManager.addOrUpdateNetwork干了啥即可(如果是新网络则添加,如果是存在过的,则比对,不同则更新),然后 transitionTo(mL3ProvisioningState)状态里,而从上面的状态图我们可以知道L3ProvisioningState的父状态是 L2ConnectedState,所以先看 L2ConnectedState的enter方法:
class L2ConnectedState extends State {
@Override
public void enter() {
mRssiPollToken++;
if (mEnableRssiPolling) {
if (isPrimary()) {
mLinkProbeManager.resetOnNewConnection();
}
sendMessage(CMD_RSSI_POLL, mRssiPollToken, 0);
}
sendNetworkChangeBroadcast(DetailedState.CONNECTING);
// If this network was explicitly selected by the user, evaluate whether to inform
// ConnectivityService of that fact so the system can treat it appropriately.
final WifiConfiguration config = getConnectedWifiConfigurationInternal();
final NetworkAgentConfig naConfig = getNetworkAgentConfigInternal(config);
final NetworkCapabilities nc = getCapabilities(
getConnectedWifiConfigurationInternal(), getConnectedBssidInternal());
// This should never happen.
if (mNetworkAgent != null) {
Log.wtf(getTag(), "mNetworkAgent is not null: " + mNetworkAgent);
mNetworkAgent.unregister();
}
mNetworkAgent = mWifiInjector.makeWifiNetworkAgent(nc, mLinkProperties, naConfig,
mNetworkFactory.getProvider(), new WifiNetworkAgentCallback());
mWifiScoreReport.setNetworkAgent(mNetworkAgent);
if (SdkLevel.isAtLeastT()) {
mQosPolicyRequestHandler.setNetworkAgent(mNetworkAgent);
}
// We must clear the config BSSID, as the wifi chipset may decide to roam
// from this point on and having the BSSID specified in the network block would
// cause the roam to faile and the device to disconnect
clearTargetBssid("L2ConnectedState");
mWifiMetrics.setWifiState(mInterfaceName, WifiMetricsProto.WifiLog.WIFI_ASSOCIATED);
mWifiScoreCard.noteNetworkAgentCreated(mWifiInfo,
mNetworkAgent.getNetwork().getNetId());
mWifiBlocklistMonitor.handleBssidConnectionSuccess(mLastBssid, mWifiInfo.getSSID());
// too many places to record connection failure with too many failure reasons.
// So only record success here.
mWifiMetrics.noteFirstL2ConnectionAfterBoot(true);
mCmiMonitor.onL2Connected(mClientModeManager);
mIsLinkedNetworkRoaming = false;
}
// 上面父状态执行完,我们再看L3ProvisioningState状态的enter方法:
class L3ProvisioningState extends State {
@Override
public void enter() {
if (mInsecureEapNetworkHandler.startUserApprovalIfNecessary(mIsUserSelected)) {
return;
}
startL3Provisioning(); ---> 看这个方法
}
private void startL3Provisioning() {
WifiConfiguration currentConfig = getConnectedWifiConfigurationInternal();
if (mIpClientWithPreConnection && mIpClient != null) {
mIpClient.notifyPreconnectionComplete(mSentHLPs);
mIpClientWithPreConnection = false;
mSentHLPs = false;
} else {
startIpClient(currentConfig, false); ---> 启动IpClient,接着看这个
}
// Get Link layer stats so as we get fresh tx packet counters
getWifiLinkLayerStats();
}
// 看下 startIpClient 的实现:
private boolean startIpClient(WifiConfiguration config, boolean isFilsConnection) {
if (mIpClient == null || config == null) {
return false;
}
// 是否使用静态ip、随机mac等
final boolean isUsingStaticIp = (config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC);
final boolean isUsingMacRandomization =
config.macRandomizationSetting
!= WifiConfiguration.RANDOMIZATION_NONE
&& mWifiGlobals.isConnectedMacRandomizationEnabled();
final List<byte[]> ouis = getOuiInternal(config);
final List<android.net.DhcpOption> options =
mWifiConfigManager.getCustomDhcpOptions(WifiSsid.fromString(config.SSID), ouis);
if (mVerboseLoggingEnabled) {
final String key = config.getProfileKey();
log("startIpClient netId=" + Integer.toString(mLastNetworkId)
+ " " + key + " "
+ " roam=" + mIsAutoRoaming
+ " static=" + isUsingStaticIp
+ " randomMac=" + isUsingMacRandomization
+ " isFilsConnection=" + isFilsConnection);
}
final MacAddress currentBssid = getCurrentBssidInternalMacAddress();
final String l2Key = mLastL2KeyAndGroupHint != null
? mLastL2KeyAndGroupHint.first : null;
final String groupHint = mLastL2KeyAndGroupHint != null
? mLastL2KeyAndGroupHint.second : null;
final Layer2Information layer2Info = new Layer2Information(l2Key, groupHint,
currentBssid);
if (isFilsConnection) { ---> 是false,不走这个条件
stopIpClient();
if (isUsingStaticIp) {
mWifiNative.flushAllHlp(mInterfaceName);
return false;
}
setConfigurationsPriorToIpClientProvisioning(config);
final ProvisioningConfiguration.Builder prov =
new ProvisioningConfiguration.Builder()
.withPreDhcpAction()
.withPreconnection()
.withDisplayName(config.SSID)
.withLayer2Information(layer2Info);
if (mContext.getResources().getBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta)
|| isPrimary()) {
// unclear if the native layer will return the correct non-capabilities if APF is
// not supported on secondary interfaces.
prov.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName));
}
if (isUsingMacRandomization) {
// Use EUI64 address generation for link-local IPv6 addresses.
prov.withRandomMacAddress();
}
prov.withDhcpOptions(convertToInternalDhcpOptions(options));
mIpClient.startProvisioning(prov.build());
} else {
// 主要是发送这个广播 NETWORK_STATE_CHANGED_ACTION,携带状态
sendNetworkChangeBroadcast(DetailedState.OBTAINING_IPADDR);
// We must clear the config BSSID, as the wifi chipset may decide to roam
// from this point on and having the BSSID specified in the network block would
// cause the roam to fail and the device to disconnect.
clearTargetBssid("ObtainingIpAddress"); ---> 做一个清除的动作,防止冲突
// Stop IpClient in case we're switching from DHCP to static
// configuration or vice versa.
//
// When we transition from static configuration to DHCP in
// particular, we must tell ConnectivityService that we're
// disconnected, because DHCP might take a long time during which
// connectivity APIs such as getActiveNetworkInfo should not return
// CONNECTED.
stopDhcpSetup(); ---> 启动前先停用掉,做一个重置动作
setConfigurationsPriorToIpClientProvisioning(config);
ScanResult scanResult = getScanResultInternal(config);
final ProvisioningConfiguration.Builder prov;
ProvisioningConfiguration.ScanResultInfo scanResultInfo = null;
if (scanResult != null) {
final List<ScanResultInfo.InformationElement> ies =
new ArrayList<ScanResultInfo.InformationElement>();
for (ScanResult.InformationElement ie : scanResult.getInformationElements()) {
ScanResultInfo.InformationElement scanResultInfoIe =
new ScanResultInfo.InformationElement(ie.getId(), ie.getBytes());
ies.add(scanResultInfoIe);
}
scanResultInfo = new ProvisioningConfiguration.ScanResultInfo(scanResult.SSID,
scanResult.BSSID, ies);
}
if (!isUsingStaticIp) { ---> 不使用静态Ip
prov = new ProvisioningConfiguration.Builder()
.withPreDhcpAction() ---> 18s 超时
.withNetwork(getCurrentNetwork()) ---> 用户选择的网络
.withDisplayName(config.SSID) ---> 使用名字
.withScanResultInfo(scanResultInfo)
.withLayer2Information(layer2Info);
} else {
StaticIpConfiguration staticIpConfig = config.getStaticIpConfiguration();
prov = new ProvisioningConfiguration.Builder()
.withStaticConfiguration(staticIpConfig)
.withNetwork(getCurrentNetwork())
.withDisplayName(config.SSID)
.withLayer2Information(layer2Info);
}
// APF 过滤器配置
if (mContext.getResources().getBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta)
|| isPrimary()) {
// unclear if the native layer will return the correct non-capabilities if APF is
// not supported on secondary interfaces.
prov.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName));
}
if (isUsingMacRandomization) {
// Use EUI64 address generation for link-local IPv6 addresses.
prov.withRandomMacAddress();
}
prov.withDhcpOptions(convertToInternalDhcpOptions(options)); ---> 转换下
mIpClient.startProvisioning(prov.build()); ---> 主要看这个
}
return true;
}
继续看下这个 startProvisioning做了啥:
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/NetworkStack/src/android/net/ip/IpClient.java#819
public void startProvisioning(ProvisioningConfiguration req) {
if (!req.isValid()) {
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
return;
}
mCurrentBssid = getInitialBssid(req.mLayer2Info, req.mScanResultInfo, ShimUtils.isAtLeastS());
if (req.mLayer2Info != null) {
mL2Key = req.mLayer2Info.mL2Key;
mCluster = req.mLayer2Info.mCluster;
}
sendMessage(CMD_START, new android.net.shared.ProvisioningConfiguration(req));
}
// 先看下状态机对应层级
addState(mStoppedState);
addState(mStartedState);
addState(mPreconnectingState, mStartedState);
addState(mClearingIpAddressesState, mStartedState);
addState(mRunningState, mStartedState);
addState(mStoppingState);
// CHECKSTYLE:ON IndentationCheck
setInitialState(mStoppedState);
// 对应的处理:
case CMD_START:
mConfiguration = (android.net.shared.ProvisioningConfiguration) msg.obj;
transitionTo(mClearingIpAddressesState); ---> 父状态是mStartedState
break;
class ClearingIpAddressesState extends State {
@Override
public void enter() {
// Ensure that interface parameters are fetched on the handler thread so they are
// properly ordered with other events, such as restoring the interface MTU on teardown.
mInterfaceParams = mDependencies.getInterfaceParams(mInterfaceName);
if (mInterfaceParams == null) {
logError("Failed to find InterfaceParams for " + mInterfaceName);
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INTERFACE_NOT_FOUND);
deferMessage(obtainMessage(CMD_STOP, DisconnectCode.DC_INTERFACE_NOT_FOUND.getNumber()));
return;
}
mLinkObserver.setInterfaceParams(mInterfaceParams);
if (readyToProceed()) { ---》 首次ipv4和v6都是没有的
deferMessage(obtainMessage(CMD_ADDRESSES_CLEARED));
} else {
// Clear all IPv4 and IPv6 before proceeding to RunningState.
// Clean up any leftover state from an abnormal exit from
// tethering or during an IpClient restart.
stopAllIP();
}
mCallback.setNeighborDiscoveryOffload(true);
}
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case CMD_ADDRESSES_CLEARED:
transitionTo(isUsingPreconnection() ? mPreconnectingState : mRunningState);
break;
// isUsingPreconnection()的实现看下
private boolean isUsingPreconnection() {
return mConfiguration.mEnablePreconnection && mConfiguration.mStaticIpConfig == null;
}
// 这里不是静态的,所以肯定返回的是false,那切到的就是 mRunningState 状态
class RunningState extends State {
private ConnectivityPacketTracker mPacketTracker;
private boolean mDhcpActionInFlight;
@Override
public void enter() {
ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
apfConfig.multicastFilter = mMulticastFiltering;
// Get the Configuration for ApfFilter from Context
// Resource settings were moved from ApfCapabilities APIs to NetworkStack resources in S
if (ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.R)) {
final Resources res = mContext.getResources();
apfConfig.ieee802_3Filter = res.getBoolean(R.bool.config_apfDrop802_3Frames);
apfConfig.ethTypeBlackList = res.getIntArray(R.array.config_apfEthTypeDenyList);
} else {
apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
}
apfConfig.minRdnssLifetimeSec = mMinRdnssLifetimeSec;
mApfFilter = mDependencies.maybeCreateApfFilter(mContext, apfConfig, mInterfaceParams,
mCallback);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
if (mApfFilter == null) {
mCallback.setFallbackMulticastFilter(mMulticastFiltering);
}
mPacketTracker = createPacketTracker();
if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
final int acceptRa =
mConfiguration.mIPv6ProvisioningMode == PROV_IPV6_LINKLOCAL ? 0 : 2;
if (isIpv6Enabled() && !startIPv6(acceptRa)) {
doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV6);
return;
}
if (isIpv4Enabled() && !isUsingPreconnection() && !startIPv4()) { ---> 看ipv4的获取
doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4);
enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV4);
return;
}
final InitialConfiguration config = mConfiguration.mInitialConfig;
if ((config != null) && !applyInitialConfig(config)) {
// TODO introduce a new IpManagerEvent constant to distinguish this error case.
doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING);
enqueueJumpToStoppingState(DisconnectCode.DC_INVALID_PROVISIONING);
return;
}
if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) {
doImmediateProvisioningFailure(
IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR);
enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPREACHABILITYMONITOR);
return;
}
}
// 看ipv4的获取:
private boolean startIPv4() {
// If we have a StaticIpConfiguration attempt to apply it and
// handle the result accordingly.
if (mConfiguration.mStaticIpConfig != null) { ---> 非静态,所以不走这个条件
if (mInterfaceCtrl.setIPv4Address(mConfiguration.mStaticIpConfig.getIpAddress())) {
handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
} else {
return false;
}
} else {
if (mDhcpClient != null) {
Log.wtf(mTag, "DhcpClient should never be non-null in startIPv4()");
}
startDhcpClient(); ---> 看这个函数
}
return true;
}
private void startDhcpClient() {
// Start DHCPv4.
mDhcpClient = mDependencies.makeDhcpClient(mContext, IpClient.this, mInterfaceParams,
mDependencies.getDhcpClientDependencies(mIpMemoryStore, mIpProvisioningMetrics));
// Check if the vendor-specific IE oui/type matches and filters the customized DHCP options.
final List<DhcpOption> options = maybeFilterCustomizedDhcpOptions();
// If preconnection is enabled, there is no need to ask Wi-Fi to disable powersaving
// during DHCP, because the DHCP handshake will happen during association. In order to
// ensure that future renews still do the DHCP action (if configured),
// registerForPreDhcpNotification is called later when processing the CMD_*_PRECONNECTION
// messages.
if (!isUsingPreconnection()) mDhcpClient.registerForPreDhcpNotification();
// 这不就是熟悉的味道了么: DhcpClient.CMD_START_DHCP
mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP, new DhcpClient.Configuration(mL2Key, isUsingPreconnection(), options));
}
后面的流程用文字总结下就是:IpClient 中发送 CMD_START_DHCP 在DhcpClient 中 StoppedState 里面处理
StoppedState —> WaitBeforeObtainingConfigurationState —> ObtainingConfigurationState —> DhcpInitState —> DhcpRequestingState —> ConfiguringInterfaceState —> DhcpBoundState
其中 DhcpInitState 里面 是处理发包(Broadcasting DHCPDISCOVER)和收包,DhcpRequestingState 里面处理发包(DHCPREQUEST)和收包
到此我们就大致梳理了DHCP的流程,当然文字描述比较简单,但代码实际内容还是挺多的,可以细看下代码。