android p wifi一直在扫描_最全面的Android Wifi扫描分析

使用

开始wifi扫描的代码很简单:

val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

val success = wifiManager.startScan()

if (!success) {

// scan failure handling

scanFailure()

}

然后定义一个receiver接收结果

val wifiScanReceiver = object : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {

val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)

if (success) {

val results = wifiManager.scanResults

} else {

scanFailure()

}

}

}

val intentFilter = IntentFilter()

intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)

context.registerReceiver(wifiScanReceiver, intentFilter)

注意:scanFailure时,wifiManager.scanResults的数据未上一次的扫描结果

版本差异

Android 8以下:

未限制

Android 8.0 和 Android 8.1:

每个后台应用可以在 30 分钟内扫描一次。

需要申明以下任意一项权限即可:

ACCESS_FINE_LOCATION

ACCESS_COARSE_LOCATION

CHANGE_WIFI_STATE

Android 9:

每个前台应用可以在 2 分钟内扫描四次。这样便可在短时间内进行多次扫描。

所有后台应用组合可以在 30 分钟内扫描一次。

需要申明以下所有权限:

ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION

CHANGE_WIFI_STATE

设备已启用位置服务 (Settings > Location)。

Android 10 及更高版本:

用 Android 9 的节流限制。新增一个开发者选项,用户可以关闭节流功能以便进行本地测试(Developer Options > Networking > Wi-Fi scan throttling)

target>=29,必须有 ACCESS_FINE_LOCATION

target<29,ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION都可以

CHANGE_WIFI_STATE

设备已启用位置服务 (Settings > Location)。

源码解析

startScan

WifiManager类中的startScan方法:

/** @hide */

@SystemApi

@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)

public boolean startScan(WorkSource workSource) {

try {

String packageName = mContext.getOpPackageName();

mService.startScan(null, workSource, packageName);

return true;

} catch (RemoteException e) {

throw e.rethrowFromSystemServer();

}

}

最终通过IWifiManager.aidl,调用的是WifiServiceImpl类

不同系统版本有不同实现

1. Android 6.0,7.0系统:

public void startScan(ScanSettings settings, WorkSource workSource) {

enforceChangePermission();

synchronized (this) {

if (mInIdleMode) {

// Need to send an immediate scan result broadcast in case the

// caller is waiting for a result ..

// clear calling identity to send broadcast

long callingIdentity = Binder.clearCallingIdentity();

try {

mWifiStateMachine.sendScanResultsAvailableBroadcast(/* scanSucceeded = */ false);

} finally {

// restore calling identity

Binder.restoreCallingIdentity(callingIdentity);

}

mScanPending = true;

return;

}

}

...

mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,

settings, workSource);

}

enforceChangePermission是检查是否有CHANGE_WIFI_STATE的权限

mInIdleMode由powermanager判定设备是否处于空闲状态

如果处于空闲,则不再真正扫描,而是调用WifiStateMachine发送最近可用的扫描结果

我们看下WifiStateMachine的代码:

/**

* Track the state of Wifi connectivity. All event handling is done here,

* and all changes in connectivity state are initiated here.

*

* Wi-Fi now supports three modes of operation: Client, SoftAp and p2p

* In the current implementation, we support concurrent wifi p2p and wifi operation.

* The WifiStateMachine handles SoftAp and Client operations while WifiP2pService

* handles p2p operation.

*

* @hide

*/

public class WifiStateMachine extends StateMachine implements WifiNative.WifiRssiEventHandler {

...

public void startScan(int callingUid, int scanCounter,

ScanSettings settings, WorkSource workSource) {

Bundle bundle = new Bundle();

bundle.putParcelable(CUSTOMIZED_SCAN_SETTING, settings);

bundle.putParcelable(CUSTOMIZED_SCAN_WORKSOURCE, workSource);

bundle.putLong(SCAN_REQUEST_TIME, System.currentTimeMillis());

sendMessage(CMD_START_SCAN, callingUid, scanCounter, bundle);

}

...

}

这个类主要维护Wifi连接的各种状态,以及所有事件的处理

其中维护了ScanModeState,DriverStartedState,DriverStartingState,ConnectModeState等等

在ScanModeState中的processMessage方法调用了handleScanRequest方法:

class ScanModeState extends State {

...

@Override

public boolean processMessage(Message message) {

// Handle scan. All the connection related commands are

// handled only in ConnectModeState

case CMD_START_SCAN:

handleScanRequest(message);

break;

}

}

private void handleScanRequest(Message message) {

...

// call wifi native to start the scan

if (startScanNative(freqs, hiddenNetworkIds, workSource)) {

// a full scan covers everything, clearing scan request buffer

if (freqs == nu

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值