跟踪WifiManager.connect流程
基于android 9.0 pk3.0
连接wifi调用sdk接口
wifiManager.connect
/**
* 连接一个network通过network
*
* 这个方法被用来代替 enableNetwork() and reconnect()
*
* @param networkId the ID of the network as returned by {@link #addNetwork} or {@link
* getConfiguredNetworks}.
* @param 连接回调,可以是null
* @throws IllegalStateException if the WifiManager instance needs to be
* initialized again
* @hide
*/
public void connect(int networkId, ActionListener listener) {
if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
getChannel().sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
}
/**
* 连接网络通过configuration. 这个网络也会添加到前台用户配置的的网络列表当中
*
* 一个新的网络,这个方法用来代替addNetwork(), enableNetwork(), and reconnect()
*
* @param config the set of variables that describe the configuration,
* contained in a {@link WifiConfiguration} object.
* @param listener for callbacks on success or failure. Can be null.
* @throws IllegalStateException if the WifiManager instance needs to be
* initialized again
*
* @hide
*/
@SystemApi
public void connect(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
// Use INVALID_NETWORK_ID for arg1 when passing a config object
// arg1 is used to pass network id when the network already exists
getChannel().sendMessage(CONNECT_NETWORK, WifiConfiguration.INVALID_NETWORK_ID,
putListener(listener), config);
}
sdk提供的两个方法最后都是CONNECT_NETWORK发消息出去了。
getChanel是AsyncChannel
/**
* Send a message to the destination handler
*
* @param what
* @param arg1
* @param arg2
* @param obj
*/
public void sendMessage(int what, int arg1, int arg2, Object obj) {
Message msg = Message.obtain();
msg.what = what;
msg.arg1 = arg1;
msg.arg2 = arg2;
msg.obj = obj;
sendMessage(msg);
}
看下sendMessage(msg)
/**
* Send a message to the destination handler.
*
* @param msg
*/
public void sendMessage(Message msg) {
msg.replyTo = mSrcMessenger;
try {
mDstMessenger.send(msg);
} catch (RemoteException e) {
replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
}
}
看下mDstMessenger是什么
/**
* Connect handler to messenger. This method is typically called
* when a server receives a CMD_CHANNEL_FULL_CONNECTION request
* and initializes the internal instance variables to allow communication
* with the dstMessenger.
*
* @param srcContext
* @param srcHandler
* @param dstMessenger
*/
public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
if (DBG) log("connected srcHandler to the dstMessenger E");
// Initialize source fields
mSrcContext = srcContext;
mSrcHandler = srcHandler;
mSrcMessenger = new Messenger(mSrcHandler);
// Initialize destination fields
mDstMessenger = dstMessenger;
if (DBG) log("connected srcHandler to the dstMessenger X");
}
看下WifiManager有没有调用传入dstMessenger
private synchronized AsyncChannel getChannel() {
if (mAsyncChannel == null) {
Messenger messenger = getWifiServiceMessenger();
if (messenger == null) {
throw new IllegalStateException(
"getWifiServiceMessenger() returned null! This is invalid.");
}
mAsyncChannel = new AsyncChannel();
mConnected = new CountDownLatch(1);
Handler handler = new ServiceHandler(mLooper);
mAsyncChannel.connect(mContext, handler, messenger);
try {
mConnected.await();
} catch (InterruptedException e) {
Log.e(TAG, "interrupted wait at init");
}
}
return mAsyncChannel;
}
getWifiServiceMessenger这个方法就是mstMessage
/**
* Get a reference to WifiService handler. This is used by a client to establish
* an AsyncChannel communication with WifiService
*
* @return Messenger pointing to the WifiService handler
* @hide
*/
public Messenger getWifiServiceMessenger() {
try {
return mService.getWifiServiceMessenger(mContext.getOpPackageName());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
然后我们转由去实现WifiServiceImpl.Java,为什么找到这个类,不知道有没有人有比较巧的方法去找aidl的实现,我是通过全局搜索继承了extends IWifiManager.Stub搜到的。感觉这个方法比较蠢,不知道有没有比较高效的方法。
/**
* Get a reference to handler. This is used by a client to establish
* an AsyncChannel communication with WifiService
*/
@Override
public Messenger getWifiServiceMessenger(String packageName) throws RemoteException {
enforceAccessPermission();
if (enforceChangePermission(packageName) != MODE_ALLOWED) {
// We don't have a good way of creating a fake Messenger, and returning null would
// immediately break callers.
throw new SecurityException("Could not create wifi service messenger");
}
mLog.info("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush();
return new Messenger(mClientHandler);
}
看下mClientHandler是什么
case WifiManager.CONNECT_NETWORK: {
if (checkChangePermissionAndReplyIfNotAuthorized(
msg, WifiManager.CONNECT_NETWORK_FAILED)) {
WifiConfiguration config = (WifiConfiguration) msg.obj;
int networkId = msg.arg1;
Slog.d(TAG, "CONNECT "
+ " nid=" + Integer.toString(networkId)
+ " config=" + config
+ " uid=" + msg.sendingUid
+ " name="
+ mContext.getPackageManager().getNameForUid(msg.sendingUid));
if (config != null) {
/* Command is forwarded to state machine */
mWifiStateMachine.sendMessage(Message.obtain(msg));
} else if (config == null
&& networkId != WifiConfiguration.INVALID_NETWORK_ID) {
mWifiStateMachine.sendMessage(Message.obtain(msg));
} else {
Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.INVALID_ARGS);
}
}
break;
}
终于到这边了,监听到CONNECT_NETWORK请求,要去搞事情了。
这里鉴权,看有没有权限开启wifi,然后打印一下log,就交由wifiStateMachine处理了。
接下来看下状态机又要做什么
wifiStateMachine没有sendMessage方法,去父类StateMachine看看
/**
* Enqueue a message to this state machine.
*
* Message is ignored if state machine has quit.
*/
public void sendMessage(Message msg) {
// mSmHandler can be null if the state machine has quit.
SmHandler smh = mSmHandler;
if (smh == null) return;
smh.sendMessage(msg);
}
又来了,mSmHandler是什么,哪里传的
/**
* Initialize.
*
* @param looper for this state machine
* @param name of the state machine
*/
private void initStateMachine(String name, Looper looper) {
mName = name;
mSmHandler = new SmHandler(looper, this);
}
这个是私有方法,看下SmHandler
private static class SmHandler extends Handler {}
SmHandler就是个普通的handler,那前面去sendMessage,我们直接看handleMessage
/**
* 将消息发给状态机processMessage,
* 同时也处理进入和退出切换状态机状态。
*/
@Override
public final void handleMessage(Message msg) {
if (!mHasQuit) {
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPreHandleMessage(msg);
}
if (mDbg) mSm.log("handleMessage: E msg.what=" + msg.what);
/** Save the current message */
mMsg = msg;
/** State that processed the message */
State msgProcessedState = null;
if (mIsConstructionCompleted || (mMsg.what == SM_QUIT_CMD)) {
/** Normal path */
msgProcessedState = processMsg(msg);
} else if (!mIsConstructionCompleted && (mMsg.what == SM_INIT_CMD)
&& (mMsg.obj == mSmHandlerObj)) {
/** Initial one time path. */
mIsConstructionCompleted = true;
invokeEnterMethods(0);
} else {
throw new RuntimeException("StateMachine.handleMessage: "
+ "The start method not called, received msg: " + msg);
}
performTransitions(msgProcessedState, msg);
// We need to check if mSm == null here as we could be quitting.
if (mDbg && mSm != null) mSm.log("handleMessage: X");
if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) {
mSm.onPostHandleMessage(msg);
}
}
}
也就是说这个消息在执行前,现预执行onPreHandleMessage(msg),然后执行processMsg,最后执行mSm.onPostHandleMessage(msg),现看下processMsg做什么
/**
* 处理消息,如果当前状态机没有处理消息,通知父类去处理。如果还是没有处理就会调用unhandleMessage方法。
*/
private final State processMsg(Message msg) {
StateInfo curStateInfo = mStateStack[mStateStackTopIndex];
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
if (isQuit(msg)) {
transitionTo(mQuittingState);
} else {
while (!curStateInfo.state.processMessage(msg)) {
/**
* Not processed
*/
curStateInfo = curStateInfo.parentStateInfo;
if (curStateInfo == null) {
/**
* No parents left so it's not handled
*/
mSm.unhandledMessage(msg);
break;
}
if (mDbg) {
mSm.log("processMsg: " + curStateInfo.state.getName());
}
}
}
return (curStateInfo != null) ? curStateInfo.state : null;
}
好了,这个类终于跟完了。现在回到状态机,是不是已经忘记要回到哪个类了呃~,那现在我们回到WifiMachineState去看onPreHandleMessage,processMessage,onPostHandleMessage。
很好,没有重写这两个onPreHandleMessage,onPostHandleMessage方法,父类也是空的。
那我们直接看processMessage,因为我们是连接,所以直接看ConnectModeState,就不跟这个状态机了,改天心情好再来一篇wifi状态机切换跟踪吧。
/* Connecting to an access point */
private State mConnectModeState = new ConnectModeState();
直接到ConnectModeState.processMessage;
[图片上传失败...(image-ac5695-1584363470016)]
case WifiManager.CONNECT_NETWORK:
/**
* 连接信息包括arg1的networkId或者是obj的config
* 一个新的network,要求config来连接
* 一个已经保存的network,只需要network
*/
netId = message.arg1;
config = (WifiConfiguration) message.obj;
boolean hasCredentialChanged = false;
// New network addition.
if (config != null) {
result = mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
if (!result.isSuccess()) {
loge("CONNECT_NETWORK adding/updating config=" + config + " failed");
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.ERROR);
break;
}
netId = result.getNetworkId();
hasCredentialChanged = result.hasCredentialChanged();
}
if (!connectToUserSelectNetwork(
netId, message.sendingUid, hasCredentialChanged)) {
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.NOT_AUTHORIZED);
break;
}
mWifiMetrics.logStaEvent(StaEvent.TYPE_CONNECT_NETWORK, config);
broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
replyToMessage(message, WifiManager.CONNECT_NETWORK_SUCCEEDED);
break;
按照代码顺序,先看传入config的吧
WifiConfigManager.addOrUpdateNetwork
/**
* 添加/更新一个network配置到数据库A
* 如果networkId是-1,表示没有保存过,我们就创建一条新的configuration,
* 不然就更新一个已存在configuration
* @param config provided WifiConfiguration object.
* @param uid UID of the app requesting the network addition/modification.
* @return NetworkUpdateResult object representing status of the update.
*/
public NetworkUpdateResult addOrUpdateNetwork(WifiConfiguration config, int uid) {
if (!doesUidBelongToCurrentUser(uid)) {
Log.e(TAG, "UID " + uid + " not visible to the current user");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
if (config == null) {
Log.e(TAG, "Cannot add/update network with null config");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
if (mPendingStoreRead) {
Log.e(TAG, "Cannot add/update network before store is read!");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
NetworkUpdateResult result = addOrUpdateNetworkInternal(config, uid);
if (!result.isSuccess()) {
Log.e(TAG, "Failed to add/update network " + config.getPrintableSsid());
return result;
}
WifiConfiguration newConfig = getInternalConfiguredNetwork(result.getNetworkId());
sendConfiguredNetworkChangedBroadcast(
newConfig,
result.isNewNetwork()
? WifiManager.CHANGE_REASON_ADDED
: WifiManager.CHANGE_REASON_CONFIG_CHANGE);
// Unless the added network is ephemeral or Passpoint, persist the network update/addition.
if (!config.ephemeral && !config.isPasspoint()) {
saveToStore(true);
if (mListener != null) {
if (result.isNewNetwork()) {
mListener.onSavedNetworkAdded(newConfig.networkId);
} else {
mListener.onSavedNetworkUpdated(newConfig.networkId);
}
}
}
return result;
}
如果传参正确的话就会调用到 addOrUpdateNetworkInternal(config, uid);
/**
* 添加/更新一个network配置到数据库A
* 如果networkId是-1,表示没有保存过,我们就创建一条新的configuration,
* 不然就更新一个已存在configuration
*
* @param config provided WifiConfiguration object.
* @param uid UID of the app requesting the network addition/deletion.
* @return NetworkUpdateResult object representing status of the update.
*/
private NetworkUpdateResult addOrUpdateNetworkInternal(WifiConfiguration config, int uid) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Adding/Updating network " + config.getPrintableSsid());
}
WifiConfiguration newInternalConfig = null;
// First check if we already have a network with the provided network id or configKey.
//首先先检查是否已经存在networkId了。
WifiConfiguration existingInternalConfig = getInternalConfiguredNetwork(config);
// 没有找到配置,说明要去添加一个网络
if (existingInternalConfig == null) {
if (!WifiConfigurationUtil.validate(config, WifiConfigurationUtil.VALIDATE_FOR_ADD)) {
Log.e(TAG, "Cannot add network with invalid config");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
newInternalConfig = createNewInternalWifiConfigurationFromExternal(config, uid);
// 因为提供的初始配置可能为空
// 再次检查是否已经存在同样的configkey
existingInternalConfig = getInternalConfiguredNetwork(newInternalConfig.configKey());
}
// 已经存在configuration,去更新一个网络
if (existingInternalConfig != null) {
if (!WifiConfigurationUtil.validate(
config, WifiConfigurationUtil.VALIDATE_FOR_UPDATE)) {
Log.e(TAG, "Cannot update network with invalid config");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
// 鉴权
if (!canModifyNetwork(existingInternalConfig, uid)) {
Log.e(TAG, "UID " + uid + " does not have permission to update configuration "
+ config.configKey());
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
newInternalConfig =
updateExistingInternalWifiConfigurationFromExternal(
existingInternalConfig, config, uid);
}
// 鉴权
if (WifiConfigurationUtil.hasProxyChanged(existingInternalConfig, newInternalConfig)
&& !canModifyProxySettings(uid)) {
Log.e(TAG, "UID " + uid + " does not have permission to modify proxy Settings "
+ config.configKey() + ". Must have NETWORK_SETTINGS,"
+ " or be device or profile owner.");
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
// Update the keys for non-Passpoint enterprise networks. For Passpoint, the certificates
// and keys are installed at the time the provider is installed.
if (config.enterpriseConfig != null
&& config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE
&& !config.isPasspoint()) {
if (!(mWifiKeyStore.updateNetworkKeys(newInternalConfig, existingInternalConfig))) {
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
}
boolean newNetwork = (existingInternalConfig == null);
// This is needed to inform IpClient about any IP configuration changes.
boolean hasIpChanged =
newNetwork || WifiConfigurationUtil.hasIpChanged(
existingInternalConfig, newInternalConfig);
boolean hasProxyChanged =
newNetwork || WifiConfigurationUtil.hasProxyChanged(
existingInternalConfig, newInternalConfig);
// Reset the |hasEverConnected| flag if the credential parameters changed in this update.
boolean hasCredentialChanged =
newNetwork || WifiConfigurationUtil.hasCredentialChanged(
existingInternalConfig, newInternalConfig);
if (hasCredentialChanged) {
newInternalConfig.getNetworkSelectionStatus().setHasEverConnected(false);
}
// Add it to our internal map. This will replace any existing network configuration for
// updates.
try {
mConfiguredNetworks.put(newInternalConfig);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Failed to add network to config map", e);
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
if (mDeletedEphemeralSSIDs.remove(config.SSID)) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "Removed from ephemeral blacklist: " + config.SSID);
}
}
// Stage the backup of the SettingsProvider package which backs this up.
mBackupManagerProxy.notifyDataChanged();
NetworkUpdateResult result =
new NetworkUpdateResult(hasIpChanged, hasProxyChanged, hasCredentialChanged);
result.setIsNewNetwork(newNetwork);
result.setNetworkId(newInternalConfig.networkId);
localLog("addOrUpdateNetworkInternal: added/updated config."
+ " netId=" + newInternalConfig.networkId
+ " configKey=" + newInternalConfig.configKey()
+ " uid=" + Integer.toString(newInternalConfig.creatorUid)
+ " name=" + newInternalConfig.creatorName);
return result;
}
如果一切顺利的话最后会走到new NetworkUpdateResult(hasIpChanged, hasProxyChanged, hasCredentialChanged);返回NetworkUpdateResult回去
回到状态机case WifiManager.CONNECT_NETWORK
走到connectToUserSelectNetwork( netId, message.sendingUid, hasCredentialChanged)
/**
* 初始化网络连接,需要检查NETWORK_SETTINGS permission.
*/
private boolean connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect) {
logd("connectToUserSelectNetwork netId " + netId + ", uid " + uid
+ ", forceReconnect = " + forceReconnect);
if (mWifiConfigManager.getConfiguredNetwork(netId) == null) {
loge("connectToUserSelectNetwork Invalid network Id=" + netId);
return false;
}
if (!mWifiConfigManager.enableNetwork(netId, true, uid)
|| !mWifiConfigManager.updateLastConnectUid(netId, uid)) {
logi("connectToUserSelectNetwork Allowing uid " + uid
+ " with insufficient permissions to connect=" + netId);
} else if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
// Note user connect choice here, so that it will be considered in the next network
// selection.
mWifiConnectivityManager.setUserConnectChoice(netId);
}
if (!forceReconnect && mWifiInfo.getNetworkId() == netId) {
// We're already connected to the user specified network, don't trigger a
// reconnection unless it was forced.
logi("connectToUserSelectNetwork already connecting/connected=" + netId);
} else {
mWifiConnectivityManager.prepareForForcedConnection(netId);
startConnectToNetwork(netId, uid, SUPPLICANT_BSSID_ANY);
}
return true;
}
看下这个方法mWifiConnectivityManager.prepareForForcedConnection(netId);
/**
* Handler to prepare for connection to a user or app specified network
*/
public void prepareForForcedConnection(int netId) {
localLog("prepareForForcedConnection: netId=" + netId);
clearConnectionAttemptTimeStamps();
clearBssidBlacklist();
}
好像没什么关键的,下一个startConnectToNetwork(netId, uid, SUPPLICANT_BSSID_ANY);
/**
* 连接指定的wifi
*
* @param networkId ID of the network to connect to
* @param uid UID of the app triggering the connection.
* @param bssid BSSID of the network
*/
public void startConnectToNetwork(int networkId, int uid, String bssid) {
sendMessage(CMD_START_CONNECT, networkId, uid, bssid);
}
又来了,现在看下CMD_START_CONNECT
case CMD_START_CONNECT:
/* connect command coming from auto-join */
netId = message.arg1;
int uid = message.arg2;
bssid = (String) message.obj;
synchronized (mWifiReqCountLock) {
if (!hasConnectionRequests()) {
if (mNetworkAgent == null) {
loge("CMD_START_CONNECT but no requests and not connected,"
+ " bailing");
break;
} else if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
loge("CMD_START_CONNECT but no requests and connected, but app "
+ "does not have sufficient permissions, bailing");
break;
}
}
}
config = mWifiConfigManager.getConfiguredNetworkWithoutMasking(netId);
logd("CMD_START_CONNECT sup state "
+ mSupplicantStateTracker.getSupplicantStateName()
+ " my state " + getCurrentState().getName()
+ " nid=" + Integer.toString(netId)
+ " roam=" + Boolean.toString(mIsAutoRoaming));
if (config == null) {
loge("CMD_START_CONNECT and no config, bail out...");
break;
}
mTargetNetworkId = netId;
setTargetBssid(config, bssid);
if (mEnableConnectedMacRandomization.get()) {
configureRandomizedMacAddress(config);
}
String currentMacAddress = mWifiNative.getMacAddress(mInterfaceName);
mWifiInfo.setMacAddress(currentMacAddress);
Log.i(TAG, "Connecting with " + currentMacAddress + " as the mac address");
reportConnectionAttemptStart(config, mTargetRoamBSSID,
WifiMetricsProto.ConnectionEvent.ROAM_UNRELATED);
if (mWifiNative.connectToNetwork(mInterfaceName, config)) {
mWifiMetrics.logStaEvent(StaEvent.TYPE_CMD_START_CONNECT, config);
lastConnectAttemptTimestamp = mClock.getWallClockMillis();
targetWificonfiguration = config;
mIsAutoRoaming = false;
if (getCurrentState() != mDisconnectedState) {
transitionTo(mDisconnectingState);
}
} else {
loge("CMD_START_CONNECT Failed to start connection to network " + config);
reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_CONNECT_NETWORK_FAILED,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
replyToMessage(message, WifiManager.CONNECT_NETWORK_FAILED,
WifiManager.ERROR);
break;
}
break;
这边可以看到mWifiNative.connectToNetwork(mInterfaceName, config)就去连接网络了。跟到neative就不跟了,反正我也看不懂╮(╯▽╰)╭.
这样就完成connect config的流程。
那如果是networkId!=-1的呢?回来CONNECT_NETWORK,其实刚刚已经分析完了,就是顺着走,在没有保存config的时候,保存一下config,这样获取networkId就不会是-1,然后走连接流程。
image.png接下来分析wifiManager.save流程
WifiManager.save
/**
* 保存config ,如果当前配置已经有了,就做更新,
* 一个新的配置,会默认设置为enabled
* For an existing network, it accomplishes the task of updateNetwork()
* 这个api会造成重连如果当前的证书有change
* @hide
*/
public void save(WifiConfiguration config, ActionListener listener) {
if (config == null) throw new IllegalArgumentException("config cannot be null");
getChannel().sendMessage(SAVE_NETWORK, 0, putListener(listener), config);
}
因为这边已经分析过了,所以直接到WifiStateMachine吧
case WifiManager.SAVE_NETWORK:
result = saveNetworkConfigAndSendReply(message);
netId = result.getNetworkId();
if (result.isSuccess() && mWifiInfo.getNetworkId() == netId) {
if (result.hasCredentialChanged()) {
config = (WifiConfiguration) message.obj;
// The network credentials changed and we're connected to this network,
// start a new connection with the updated credentials.
logi("SAVE_NETWORK credential changed for config=" + config.configKey()
+ ", Reconnecting.");
startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
} else {
if (result.hasProxyChanged()) {
log("Reconfiguring proxy on connection");
mIpClient.setHttpProxy(
getCurrentWifiConfiguration().getHttpProxy());
}
if (result.hasIpChanged()) {
// The current connection configuration was changed
// We switched from DHCP to static or from static to DHCP, or the
// static IP address has changed.
log("Reconfiguring IP on connection");
// TODO(b/36576642): clear addresses and disable IPv6
// to simplify obtainingIpState.
transitionTo(mObtainingIpState);
}
}
}
break;
看下这个方法saveNetworkConfigAndSendReply(message)
/**
* 私有的方法去调用add & enable network
*
* @return NetworkUpdateResult with networkId of the added/updated configuration. Will return
* {@link WifiConfiguration#INVALID_NETWORK_ID} in case of error.
*/
private NetworkUpdateResult saveNetworkConfigAndSendReply(Message message) {
WifiConfiguration config = (WifiConfiguration) message.obj;
if (config == null) {
loge("SAVE_NETWORK with null configuration "
+ mSupplicantStateTracker.getSupplicantStateName()
+ " my state " + getCurrentState().getName());
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
NetworkUpdateResult result =
mWifiConfigManager.addOrUpdateNetwork(config, message.sendingUid);
if (!result.isSuccess()) {
loge("SAVE_NETWORK adding/updating config=" + config + " failed");
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
return result;
}
if (!mWifiConfigManager.enableNetwork(
result.getNetworkId(), false, message.sendingUid)) {
loge("SAVE_NETWORK enabling config=" + config + " failed");
messageHandlingStatus = MESSAGE_HANDLING_STATUS_FAIL;
replyToMessage(message, WifiManager.SAVE_NETWORK_FAILED, WifiManager.ERROR);
return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
}
broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
replyToMessage(message, WifiManager.SAVE_NETWORK_SUCCEEDED);
return result;
}
addOrUpdateNetwork这个方法很熟悉,前面已经分析过了,不在赘述
这边save的逻辑还有一个,如果满足这个条件,就会在保存之后发起连接过程。
if (result.isSuccess() && mWifiInfo.getNetworkId() == netId) {
if (result.hasCredentialChanged()) {
config = (WifiConfiguration) message.obj;
// The network credentials changed and we're connected to this network,
// start a new connection with the updated credentials.
logi("SAVE_NETWORK credential changed for config=" + config.configKey()
+ ", Reconnecting.");
startConnectToNetwork(netId, message.sendingUid, SUPPLICANT_BSSID_ANY);
}
}
先看下这个是什么:mWifiInfo.getNetworkId()
去WifiInfo.java,
/** @hide */
public void setNetworkId(int id) {
mNetworkId = id;
}
就这么个入口,还是回到刚刚的地方
这边有5处调用setNetworkId的地方,第一二处
if (SupplicantState.isConnecting(state)) {
mWifiInfo.setNetworkId(stateChangeResult.networkId);
mWifiInfo.setBSSID(stateChangeResult.BSSID);
mWifiInfo.setSSID(stateChangeResult.wifiSsid);
} else {
// Reset parameters according to WifiInfo.reset()
mWifiInfo.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
mWifiInfo.setBSSID(null);
mWifiInfo.setSSID(null);
}
处于connecting的状态下,会把连接中的networkId设置进去,后面是设置成-1,与我们的要求不符合
第三处:ConnectModeState.processMessage
case WifiMonitor.NETWORK_CONNECTION_EVENT:
if (mVerboseLoggingEnabled) log("Network connection established");
mLastNetworkId = message.arg1;
mWifiConfigManager.clearRecentFailureReason(mLastNetworkId);
mLastBssid = (String) message.obj;
reasonCode = message.arg2;
// TODO: This check should not be needed after WifiStateMachinePrime r
// Currently, the last connected network configuration is left in
// wpa_supplicant, this may result in wpa_supplicant initiating connec
// to it after a config store reload. Hence the old network Id lookups
// work, so disconnect the network and let network selector reselect a
// network.
config = getCurrentWifiConfiguration();
if (config != null) {
mWifiInfo.setBSSID(mLastBssid);
mWifiInfo.setNetworkId(mLastNetworkId);
mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName))
ScanDetailCache scanDetailCache =
mWifiConfigManager.getScanDetailCacheForNetwork(config.net
if (scanDetailCache != null && mLastBssid != null) {
ScanResult scanResult = scanDetailCache.getScanResult(mLastBss
if (scanResult != null) {
mWifiInfo.setFrequency(scanResult.frequency);
}
}
mWifiConnectivityManager.trackBssid(mLastBssid, true, reasonCode);
// We need to get the updated pseudonym from supplicant for EAP-SI
if (config.enterpriseConfig != null
&& TelephonyUtil.isSimEapMethod(
config.enterpriseConfig.getEapMethod())) {
String anonymousIdentity =
mWifiNative.getEapAnonymousIdentity(mInterfaceName);
if (anonymousIdentity != null) {
config.enterpriseConfig.setAnonymousIdentity(anonymousIden
} else {
Log.d(TAG, "Failed to get updated anonymous identity"
+ " from supplicant, reset it in WifiConfiguration
config.enterpriseConfig.setAnonymousIdentity(null);
}
mWifiConfigManager.addOrUpdateNetwork(config, Process.WIFI_UID
}
sendNetworkStateChangeBroadcast(mLastBssid);
transitionTo(mObtainingIpState);
} else {
logw("Connected to unknown networkId " + mLastNetworkId
+ ", disconnecting...");
sendMessage(CMD_DISCONNECT);
}
break;
看代码的意思是连上wifi了,下一步是获取wifi ip的样子。
第四处L2ConnectedState.processMessage
case WifiMonitor.NETWORK_CONNECTION_EVENT:
mWifiInfo.setBSSID((String) message.obj);
mLastNetworkId = message.arg1;
mWifiInfo.setNetworkId(mLastNetworkId);
mWifiInfo.setMacAddress(mWifiNative.getMacAddress(mInterfaceName));
if(!mLastBssid.equals(message.obj)) {
mLastBssid = (String) message.obj;
sendNetworkStateChangeBroadcast(mLastBssid);
}
break;
第五处:RoamingState.processMessage
case WifiMonitor.NETWORK_CONNECTION_EVENT:
if (mAssociated) {
if (mVerboseLoggingEnabled) {
log("roaming and Network connection established");
}
mLastNetworkId = message.arg1;
mLastBssid = (String) message.obj;
mWifiInfo.setBSSID(mLastBssid);
mWifiInfo.setNetworkId(mLastNetworkId);
int reasonCode = message.arg2;
mWifiConnectivityManager.trackBssid(mLastBssid, true, reasonCode);
sendNetworkStateChangeBroadcast(mLastBssid);
// Successful framework roam! (probably)
reportConnectionAttemptEnd(
WifiMetrics.ConnectionEvent.FAILURE_NONE,
WifiMetricsProto.ConnectionEvent.HLF_NONE);
// We must clear the config BSSID, as the wifi chipset may decide to roam
// from this point on and having the BSSID specified by QNS would cause
// the roam to fail and the device to disconnect.
// When transition from RoamingState to DisconnectingState or
// DisconnectedState, the config BSSID is cleared by
// handleNetworkDisconnect().
clearTargetBssid("RoamingCompleted");
// We used to transition to ObtainingIpState in an
// attempt to do DHCPv4 RENEWs on framework roams.
// DHCP can take too long to time out, and we now rely
// upon IpClient's use of IpReachabilityMonitor to
// confirm our current network configuration.
//
// mIpClient.confirmConfiguration() is called within
// the handling of SupplicantState.COMPLETED.
transitionTo(mConnectedState);
} else {
messageHandlingStatus = MESSAGE_HANDLING_STATUS_DISCARD;
}
break;
总而言之,这个networkId都是在收到消息NETWORK_CONNECTION_EVENT才赋值,去WifiMonitor看下对消息值的定义
/* Network connection completed */
public static final int NETWORK_CONNECTION_EVENT = BASE + 3;
也就是说,本地wifi要和远程WiFi建立连接之后才能相等。也就是说connect和save都很多相同点
connect=save+(热点之前已经建立连接的修改网络配置)
image.png
网友评论