看过之前SoftAp流程的,我们都知道界面打开按钮后,最终会调到SoftApManager这个类里面,这里我们选用Android 13的代码看下:
http://aospxref.com/android-13.0.0_r3/xref/packages/modules/Wifi/service/java/com/android/server/wifi/SoftApManager.java
private int startSoftAp() {
Log.d(getTag(), "startSoftAp: band " + mCurrentSoftApConfiguration.getBand()
+ " iface " + mApInterfaceName + " country " + mCountryCode);
int result = setMacAddress();
if (result != SUCCESS) {
return result;
}
result = setCountryCode();
if (result != SUCCESS) {
return result;
}
// Make a copy of configuration for updating AP band and channel.
SoftApConfiguration.Builder localConfigBuilder =
new SoftApConfiguration.Builder(mCurrentSoftApConfiguration);
result = ApConfigUtil.updateApChannelConfig(
mWifiNative, mCoexManager, mContext.getResources(), mCountryCode,
localConfigBuilder, mCurrentSoftApConfiguration, mCurrentSoftApCapability);
if (result != SUCCESS) {
Log.e(getTag(), "Failed to update AP band and channel");
return result;
}
if (mCurrentSoftApConfiguration.isHiddenSsid()) {
Log.d(getTag(), "SoftAP is a hidden network");
}
if (!ApConfigUtil.checkSupportAllConfiguration(
mCurrentSoftApConfiguration, mCurrentSoftApCapability)) {
Log.d(getTag(), "Unsupported Configuration detect! config = "
+ mCurrentSoftApConfiguration);
return ERROR_UNSUPPORTED_CONFIGURATION;
}
// 主要看下这里面的参数
if (!mWifiNative.startSoftAp(mApInterfaceName, ---> 接口名
localConfigBuilder.build(), ---> config 配置
mOriginalModeConfiguration.getTargetMode() == WifiManager.IFACE_IP_MODE_TETHERED,
mSoftApHalCallback)) { ---> 回调函数
Log.e(getTag(), "Soft AP start failed");
return ERROR_GENERIC;
}
mWifiDiagnostics.startLogging(mApInterfaceName);
mStartTimestamp = FORMATTER.format(new Date(System.currentTimeMillis()));
Log.d(getTag(), "Soft AP is started ");
return SUCCESS;
}
看下这个注册下去的回调函数:mSoftApHalCallback:
private final SoftApHalCallback mSoftApHalCallback = new SoftApHalCallback() {
@Override
public void onFailure() {
mStateMachine.sendMessage(SoftApStateMachine.CMD_FAILURE);
}
@Override
public void onInstanceFailure(String instanceName) {
mStateMachine.sendMessage(SoftApStateMachine.CMD_FAILURE, instanceName);
}
@Override
public void onInfoChanged(String apIfaceInstance, int frequency,
@WifiAnnotations.Bandwidth int bandwidth,
@WifiAnnotations.WifiStandard int generation,
MacAddress apIfaceInstanceMacAddress) {
SoftApInfo apInfo = new SoftApInfo();
apInfo.setFrequency(frequency);
apInfo.setBandwidth(bandwidth);
apInfo.setWifiStandard(generation);
if (apIfaceInstanceMacAddress != null) {
apInfo.setBssid(apIfaceInstanceMacAddress);
}
apInfo.setApInstanceIdentifier(apIfaceInstance != null
? apIfaceInstance : mApInterfaceName);
mStateMachine.sendMessage(
SoftApStateMachine.CMD_AP_INFO_CHANGED, 0, 0, apInfo);
}
// 当有STA连接上,将回调此函数
@Override
public void onConnectedClientsChanged(String apIfaceInstance, MacAddress clientAddress, boolean isConnected) {
if (clientAddress != null) {
WifiClient client = new WifiClient(clientAddress, apIfaceInstance != null ? apIfaceInstance : mApInterfaceName);
mStateMachine.sendMessage(SoftApStateMachine.CMD_ASSOCIATED_STATIONS_CHANGED, isConnected ? 1 : 0, 0, client);
} else {
Log.e(getTag(), "onConnectedClientsChanged: Invalid type returned");
}
}
};
也就是说ClientChanged的时候就会回调此方法,然后发送CMD_ASSOCIATED_STATIONS_CHANGED消息,处理此消息的地方:
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_ASSOCIATED_STATIONS_CHANGED: ---> 处理这个消息
if (!(message.obj instanceof WifiClient)) {
Log.e(getTag(), "Invalid type returned for" + " CMD_ASSOCIATED_STATIONS_CHANGED");
break;
}
boolean isConnected = (message.arg1 == 1);
WifiClient client = (WifiClient) message.obj;
// SoftApManager[wlan0]: CMD_ASSOCIATED_STATIONS_CHANGED, Client: xx:xx:xx:xx:xx:xx isConnected: true
Log.d(getTag(), "CMD_ASSOCIATED_STATIONS_CHANGED, Client: "
+ client.getMacAddress().toString() + " isConnected: "
+ isConnected);
updateConnectedClients(client, isConnected);
break;
case CMD_AP_INFO_CHANGED:
// 执行 updateConnectedClients 方法
private void updateConnectedClients(WifiClient client, boolean isConnected) {
if (client == null) {
return;
}
if (null != mPendingDisconnectClients.remove(client)) {
Log.d(getTag(), "Remove client: " + client.getMacAddress()
+ "from pending disconnectionlist");
}
String apInstanceIdentifier = client.getApInstanceIdentifier();
List clientList = mConnectedClientWithApInfoMap.computeIfAbsent(
apInstanceIdentifier, k -> new ArrayList<>());
int index = clientList.indexOf(client);
if ((index != -1) == isConnected) {
Log.e(getTag(), "Drop client connection event, client "
+ client + "isConnected: " + isConnected
+ " , duplicate event or client is blocked");
return;
}
if (isConnected) {
// checkSoftApClient 这里面判断黑名单、最大连接数这些
boolean isAllow = checkSoftApClient(mCurrentSoftApConfiguration, client);
if (isAllow) {
clientList.add(client);
} else {
return;
}
} else {
if (null == clientList.remove(index)) {
Log.e(getTag(), "client doesn't exist in list, it should NOT happen");
}
}
// Update clients list.
mConnectedClientWithApInfoMap.put(apInstanceIdentifier, clientList);
SoftApInfo currentInfoWithClientsChanged = mCurrentSoftApInfoMap.get(apInstanceIdentifier);
// SoftApManager[wlan0]: The connected wifi stations have changed with count:
// 1: [WifiClient{mMacAddress=xx:xx:xx:xx:xx:famApInstanceIdentifier=wlan0}] on the AP which info is
// SoftApInfo {bandwidth= 2, frequency= 2432,bssid=xx:xx:xx:xx:xx, wifiStandard= 4,
// mApInstanceIdentifier= wlan0, mIdleShutdownTimeoutMillis= 600000}
Log.d(getTag(), "The connected wifi stations have changed with count: "
+ clientList.size() + ": " + clientList + " on the AP which info is "
+ currentInfoWithClientsChanged);
if (mSoftApCallback != null) {
mSoftApCallback.onConnectedClientsOrInfoChanged(mCurrentSoftApInfoMap,
mConnectedClientWithApInfoMap, isBridgeRequired());
} else {
Log.e(getTag(), "SoftApCallback is null. Dropping ConnectedClientsChanged event.");
}
mWifiMetrics.addSoftApNumAssociatedStationsChangedEvent(
getConnectedClientList().size(),
mConnectedClientWithApInfoMap.get(apInstanceIdentifier).size(),
mOriginalModeConfiguration.getTargetMode(),
mCurrentSoftApInfoMap.get(apInstanceIdentifier));
rescheduleTimeoutMessages(apInstanceIdentifier);
}
// rescheduleTimeoutMessages
private void rescheduleTimeoutMessageIfNeeded(String instance) {
final boolean isTetheringInterface = TextUtils.equals(mApInterfaceName, instance);
final boolean timeoutEnabled = isTetheringInterface ? mTimeoutEnabled
: (mBridgedModeOpportunisticsShutdownTimeoutEnabled && !mIsCharging);
final int clientNumber = isTetheringInterface
? getConnectedClientList().size()
: mConnectedClientWithApInfoMap.get(instance).size();
final long timeoutValue = isTetheringInterface
? getShutdownTimeoutMillis()
: getShutdownIdleInstanceInBridgedModeTimeoutMillis();
// SoftApManager[wlan0]: rescheduleTimeoutMessageIfNeeded wlan0, timeoutEnabled=true, isCharging false, clientNumber=1
Log.d(getTag(), "rescheduleTimeoutMessageIfNeeded " + instance + ", timeoutEnabled="
+ timeoutEnabled + ", isCharging" + mIsCharging + ", clientNumber=" + clientNumber);
if (!timeoutEnabled || clientNumber != 0) {
cancelTimeoutMessage(instance);
return;
}
scheduleTimeoutMessage(instance, timeoutValue); ---> 没有Client连接,则timeoutValue时间后关闭热点,这里的instance就是wlan0
}
OK,那我们看看app侧如何得到这个,看这样的一个方法:registerSoftApCallback
packages/modules/Wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
packages/modules/Wifi/framework/java/android/net/wifi/WifiManager.java
@RequiresPermission(anyOf = {
android.Manifest.permission.NETWORK_SETTINGS,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.OVERRIDE_WIFI_CONFIG
})
public void registerSoftApCallback(@NonNull @CallbackExecutor Executor executor, @NonNull SoftApCallback callback) {
if (executor == null) throw new IllegalArgumentException("executor cannot be null");
if (callback == null) throw new IllegalArgumentException("callback cannot be null");
Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
try {
synchronized (sSoftApCallbackMap) {
ISoftApCallback.Stub binderCallback = new SoftApCallbackProxy(executor, callback,
IFACE_IP_MODE_TETHERED);
sSoftApCallbackMap.put(System.identityHashCode(callback), binderCallback);
mService.registerSoftApCallback(binderCallback);
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//SoftApCallback callback
public interface SoftApCallback {
/**
* Called when soft AP state changes.
*
* @param state the new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
* {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
* {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
* @param failureReason reason when in failed state. One of
* {@link #SAP_START_FAILURE_GENERAL},
* {@link #SAP_START_FAILURE_NO_CHANNEL},
* {@link #SAP_START_FAILURE_UNSUPPORTED_CONFIGURATION}
*/
default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {}
/**
* Called when the connected clients to soft AP changes.
*
* @param clients the currently connected clients
*
* @deprecated This API is deprecated.
* Use {@link #onConnectedClientsChanged(SoftApInfo, List<WifiClient>)} instead.
*/
@Deprecated
default void onConnectedClientsChanged(@NonNull List<WifiClient> clients) {}
/**
* Called when the connected clients for a soft AP instance change.
*
* When the Soft AP is configured in single AP mode, this callback is invoked
* with the same {@link SoftApInfo} for all connected clients changes.
* When the Soft AP is configured as multiple Soft AP instances (using
* {@link SoftApConfiguration.Builder#setBands(int[])} or
* {@link SoftApConfiguration.Builder#setChannels(android.util.SparseIntArray)}), this
* callback is invoked with the corresponding {@link SoftApInfo} for the instance in which
* the connected clients changed.
*
* @param info The {@link SoftApInfo} of the AP.
* @param clients The currently connected clients on the AP instance specified by
* {@code info}.
*/
default void onConnectedClientsChanged(@NonNull SoftApInfo info,
@NonNull List<WifiClient> clients) {}
…………
也就是说app里面我注册即可,比如:
//调用这个接口
WifiManager.registerSoftApCallback(new HandlerExecutor(new Handler()), mSoftApCallback);
// mSoftApCallback
private WifiManager.SoftApCallback mSoftApCallback = new WifiManager.SoftApCallback() {
@Override
public void onStateChanged(int state, int failureReason) {
//处理状态改变逻辑
}
@Override
public void onConnectedClientsChanged(List<WifiClient> clients) {
//client 连接处理
}
};
至此,我们大致就可以得到连接上的Client信息了,这个信息主要就是对方的MAC地址。
————————————————
版权声明:本文为CSDN博主「奶一口仙气」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43278325/article/details/132209555