日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Wifi模块—源码分析Wifi热点扫描2(Android P)

發布時間:2025/3/15 Android 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Wifi模块—源码分析Wifi热点扫描2(Android P) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一 前言

? ? ? ?這次接著講Wifi工程流程中的Wifi熱點掃描過程部分的獲取掃描結果的過程,也是Wifi掃描過程的延續,可以先看前面Wifi掃描的分析過程。

? ? ? ? ? ? ? ? ? ? ? ? ? ?Wifi模塊—源碼分析Wifi熱點掃描(Android P)

? ? ? ? ? ? ? ? ? ? ? ? ? ??

二 圖示調用流程

? ? ? 這次的調用流程比較簡單就不畫流程圖了,而且流程是按三條不連貫的線路分析的。

三 代碼具體流程

1 底層獲取掃描結果

? ? ?在上一篇我們分析了Wifi掃描的過程。在底層完成掃描之后會通知框架層,由框架層的WifiMonitor監聽該事件并發送消息SCAN_RESULTS_EVENT,通知WificondScannerImpl進行處理,再通過WifiNative從底層獲取wifi掃描結果,最后再廣播SCAN_RESULTS_AVAILABLE_ACTION通知掃描結果可獲取。

1.1 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiMonitor.java

/**
* Broadcast scan result event to all the handlers registered for this event.
* @param iface Name of iface on which this occurred.
*/
public void broadcastScanResultEvent(String iface) {
? ? sendMessage(iface, SCAN_RESULTS_EVENT);
}
?

1.2 framework/opt/net/wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java

@Override
public boolean handleMessage(Message msg) {
? ? switch(msg.what) {
? ? ? ? case WifiMonitor.SCAN_FAILED_EVENT:
? ? ? ? ? ? Log.w(TAG, "Scan failed");
? ? ? ? ? ? cancelScanTimeout();
? ? ? ? ? ? reportScanFailure();
? ? ? ? ? ? break;
? ? ? ? case WifiMonitor.PNO_SCAN_RESULTS_EVENT:
? ? ? ? ? ? pollLatestScanDataForPno();
? ? ? ? ? ? break;
? ? ? ? case WifiMonitor.SCAN_RESULTS_EVENT:
? ? ? ? ? ? cancelScanTimeout();
? ? ? ? ? ? pollLatestScanData();
? ? ? ? ? ? break;
? ? ? ? default:
? ? ? ? ? ? // ignore unknown event
? ? }
? ? return true;
}
繼續看 pollLatestScanData。

private void pollLatestScanData() {
? ? synchronized (mSettingsLock) {
? ? ? ? if (mLastScanSettings == null) {
? ? ? ? ? ? // got a scan before we started scanning or after scan was canceled
? ? ? ? ? ? return;
? ? ? ? }
?
? ? ? ? mNativeScanResults = mWifiNative.getScanResults(mIfaceName);
? ? ? ? List<ScanResult> singleScanResults = new ArrayList<>();
? ? ? ? int numFilteredScanResults = 0;
? ? ? ? for (int i = 0; i < mNativeScanResults.size(); ++i) {
? ? ? ? ? ? ScanResult result = mNativeScanResults.get(i).getScanResult();
? ? ? ? ? ? long timestamp_ms = result.timestamp / 1000; // convert us -> ms
? ? ? ? ? ? if (timestamp_ms > mLastScanSettings.startTime) {
? ? ? ? ? ? ? ? if (mLastScanSettings.singleScanFreqs.containsChannel(
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? result.frequency)) {
? ? ? ? ? ? ? ? ? ? singleScanResults.add(result);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? numFilteredScanResults++;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? ...
? ? }
}
?通過mWifiNative.getScanResults來從底層獲取wifi熱點掃描結果。

1.3 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

/**
* Fetch the latest scan result from kernel via wificond.
* @param ifaceName Name of the interface.
* @return Returns an ArrayList of ScanDetail.
* Returns an empty ArrayList on failure.
*/
public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
? ? return mWificondControl.getScanResults(
? ? ? ? ? ? ifaceName, WificondControl.SCAN_TYPE_SINGLE_SCAN);
}
接著看mWificondControl.getScanResults。

1.4 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiNative.java

/**
* Fetch the latest scan result from kernel via wificond.
* @param ifaceName Name of the interface.
* @return Returns an ArrayList of ScanDetail.
* Returns an empty ArrayList on failure.
*/
public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName, int scanType) {
? ? ArrayList<ScanDetail> results = new ArrayList<>();
? ? IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
? ? if (scannerImpl == null) {
? ? ? ? Log.e(TAG, "No valid wificond scanner interface handler");
? ? ? ? return results;
? ? }
? ? try {
? ? ? ? NativeScanResult[] nativeResults;
? ? ? ? if (scanType == SCAN_TYPE_SINGLE_SCAN) {
? ? ? ? ? ? nativeResults = scannerImpl.getScanResults();
? ? ? ? } else {
? ? ? ? ? ? nativeResults = scannerImpl.getPnoScanResults();
? ? ? ? }
? ? ? ? ...
? ? }
? ? ...
?
? ? return results;
}
看scannerImpl.getScanResults。

1.5 system/connectivity/wificond/aidl/android/net/wifi/IWifiScannerImpl.aidl

接下來就會調到C++層,暫時就不往下分析了。

?2 通知掃描結果可獲取

接下來廣播SCAN_RESULTS_AVAILABLE_ACTION通知掃描結果可獲取。

2.1 frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java

?在這里會接收到掃描結果可獲取的廣播WifiManager.SCAN_RESULTS_AVAILABLE_ACTION。

/**
* ?Receiver for handling broadcasts.
*
* ?This receiver is registered on the WorkHandler.
*/
@VisibleForTesting
final BroadcastReceiver mReceiver = new BroadcastReceiver() {
? ? @Override
? ? public void onReceive(Context context, Intent intent) {
? ? ? ? String action = intent.getAction();
?
? ? ? ? if (WifiManager.WIFI_STATE_CHANGED_ACTION.equals(action)) {
? ? ? ? ? ? updateWifiState(
? ? ? ? ? ? ? ? ? ? intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
? ? ? ? ? ? ? ? ? ? ? ? ? ? WifiManager.WIFI_STATE_UNKNOWN));
? ? ? ? } else if (WifiManager.SCAN_RESULTS_AVAILABLE_ACTION.equals(action)) {
? ? ? ? ? ? mStaleScanResults = false;
?
? ? ? ? ? ? fetchScansAndConfigsAndUpdateAccessPoints();
? ? ? ? } else if (WifiManager.CONFIGURED_NETWORKS_CHANGED_ACTION.equals(action)
? ? ? ? ? ? ? ? || WifiManager.LINK_CONFIGURATION_CHANGED_ACTION.equals(action)) {
? ? ? ? ? ? fetchScansAndConfigsAndUpdateAccessPoints();
? ? ? ? } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) {
? ? ? ? ? ? // TODO(sghuman): Refactor these methods so they cannot result in duplicate
? ? ? ? ? ? // onAccessPointsChanged updates being called from this intent.
? ? ? ? ? ? NetworkInfo info = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
? ? ? ? ? ? updateNetworkInfo(info);
? ? ? ? ? ? fetchScansAndConfigsAndUpdateAccessPoints();
? ? ? ? } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) {
? ? ? ? ? ? NetworkInfo info =
? ? ? ? ? ? ? ? ? ? mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork());
? ? ? ? ? ? updateNetworkInfo(info);
? ? ? ? }
? ? }
};
WifiTracker接收到這個廣播后,執行fetchScansAndConfigsAndUpdateAccessPoints。

/**
* Retrieves latest scan results and wifi configs, then calls
* {@link #updateAccessPoints(List, List)}.
*/
private void fetchScansAndConfigsAndUpdateAccessPoints() {
? ? final List<ScanResult> newScanResults = mWifiManager.getScanResults();
? ? if (isVerboseLoggingEnabled()) {
? ? ? ? Log.i(TAG, "Fetched scan results: " + newScanResults);
? ? }
?
? ? List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
? ? updateAccessPoints(newScanResults, configs);
}
走到mWifiManager.getScanResults。

2.2 framework/base/wifi/java/android/net/wifi/WifiManager.java

/**
* Return the results of the latest access point scan.
* @return the list of access points found in the most recent scan. An app must hold
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
* in order to get valid results. ?If there is a remote exception (e.g., either a communication
* problem with the system service or an exception within the framework) an empty list will be
* returned.
*/
public List<ScanResult> getScanResults() {
? ? try {
? ? ? ? return mService.getScanResults(mContext.getOpPackageName());
? ? } catch (RemoteException e) {
? ? ? ? throw e.rethrowFromSystemServer();
? ? }
}
又是通過aidl進行跨進程調用mService.getScanResults。

2.3 framework/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java

/**
* Return the results of the most recent access point scan, in the form of
* a list of {@link ScanResult} objects.
* @return the list of results
*/
@Override
public List<ScanResult> getScanResults(String callingPackage) {
? ? enforceAccessPermission();
? ? int uid = Binder.getCallingUid();
? ? long ident = Binder.clearCallingIdentity();
? ? if (mVerboseLoggingEnabled) {
? ? ? ? mLog.info("getScanResults uid=%").c(uid).flush();
? ? }
? ? try {
? ? ? ? mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, uid);
? ? ? ? final List<ScanResult> scanResults = new ArrayList<>();
? ? ? ? boolean success = mWifiInjector.getWifiStateMachineHandler().runWithScissors(() -> {
? ? ? ? ? ? scanResults.addAll(mScanRequestProxy.getScanResults());
? ? ? ? }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS);
? ? ? ? if (!success) {
? ? ? ? ? ? Log.e(TAG, "Failed to post runnable to fetch scan results");
? ? ? ? }
? ? ? ? return scanResults;
? ? } catch (SecurityException e) {
? ? ? ? return new ArrayList<ScanResult>();
? ? } finally {
? ? ? ? Binder.restoreCallingIdentity(ident);
? ? }
}
返回scanResults。

這里和android O還是有一些差別的。看mScanRequestProxy.getScanResults。

2.4 framework/opt/net/wifi/service/java/com/android/server/wifi/ScanRequestProxy.java

/**
* Return the results of the most recent access point scan, in the form of
* a list of {@link ScanResult} objects.
* @return the list of results
*/
public List<ScanResult> getScanResults() {
? ? return mLastScanResults;
}
看看mLastScanResults怎么來的。

// Common scan listener for scan requests.
private class ScanRequestProxyScanListener implements WifiScanner.ScanListener {
? ? ...
? ? @Override
? ? public void onResults(WifiScanner.ScanData[] scanDatas) {
? ? ? ? if (mVerboseLoggingEnabled) {
? ? ? ? ? ? Log.d(TAG, "Scan results received");
? ? ? ? }
? ? ? ? // For single scans, the array size should always be 1.
? ? ? ? if (scanDatas.length != 1) {
? ? ? ? ? ? Log.wtf(TAG, "Found more than 1 batch of scan results, Failing...");
? ? ? ? ? ? sendScanResultBroadcastIfScanProcessingNotComplete(false);
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? WifiScanner.ScanData scanData = scanDatas[0];
? ? ? ? ScanResult[] scanResults = scanData.getResults();
? ? ? ? if (mVerboseLoggingEnabled) {
? ? ? ? ? ? Log.d(TAG, "Received " + scanResults.length + " scan results");
? ? ? ? }
? ? ? ? // Store the last scan results & send out the scan completion broadcast.
? ? ? ? mLastScanResults.clear();
? ? ? ? mLastScanResults.addAll(Arrays.asList(scanResults));
? ? ? ? sendScanResultBroadcastIfScanProcessingNotComplete(true);
? ? }
? ? ...
};
將scanResults放進LastScanResults,看scanData.getResults。WifiScanner的服務端是WifiScanningServiceImpl。

2.5 framework/base/wifi/java/android/net/wifi//WifiScanner.java

/**
* all the information garnered from a single scan
*/
public static class ScanData implements Parcelable {
?
? ? ...
? ? public ScanResult[] getResults() {
? ? ? ? return mResults;
? ? }
? ? ...
}
返回mResults。

3 Settings應用層獲取掃描結果

應用層

3.1 packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java

在生命周期函數里監聽Wifi的狀態。

@Override
public void onStart() {
? ? super.onStart();
?
? ? // On/off switch is hidden for Setup Wizard (returns null)
? ? mWifiEnabler = createWifiEnabler();
?
? ? if (mIsRestricted) {
? ? ? ? restrictUi();
? ? ? ? return;
? ? }
?
? ? onWifiStateChanged(mWifiManager.getWifiState());
}
當wifi狀態改變時會有相應的操作。

/** Called when the state of Wifi has changed. */
@Override
public void onWifiStateChanged(int state) {
? ? if (mIsRestricted) {
? ? ? ? return;
? ? }
?
? ? final int wifiState = mWifiManager.getWifiState();
? ? switch (wifiState) {
? ? ? ? case WifiManager.WIFI_STATE_ENABLED:
? ? ? ? ? ? updateAccessPointPreferences();
? ? ? ? ? ? break;
?
? ? ? ? case WifiManager.WIFI_STATE_ENABLING:
? ? ? ? ? ? removeConnectedAccessPointPreference();
? ? ? ? ? ? mAccessPointsPreferenceCategory.removeAll();
? ? ? ? ? ? addMessagePreference(R.string.wifi_starting);
? ? ? ? ? ? setProgressBarVisible(true);
? ? ? ? ? ? break;
?
? ? ? ? case WifiManager.WIFI_STATE_DISABLING:
? ? ? ? ? ? removeConnectedAccessPointPreference();
? ? ? ? ? ? mAccessPointsPreferenceCategory.removeAll();
? ? ? ? ? ? addMessagePreference(R.string.wifi_stopping);
? ? ? ? ? ? break;
?
? ? ? ? case WifiManager.WIFI_STATE_DISABLED:
? ? ? ? ? ? setOffMessage();
? ? ? ? ? ? setAdditionalSettingsSummaries();
? ? ? ? ? ? setProgressBarVisible(false);
? ? ? ? ? ? break;
? ? }
}
監聽到wifi狀態已經開啟,看updateAccessPointPreferences。

private void updateAccessPointPreferences() {
? ? // in case state has changed
? ? if (!mWifiManager.isWifiEnabled()) {
? ? ? ? return;
? ? }
? ? // AccessPoints are sorted by the WifiTracker
? ? final List<AccessPoint> accessPoints = mWifiTracker.getAccessPoints();
? ? if (isVerboseLoggingEnabled()) {
? ? ? ? Log.i(TAG, "updateAccessPoints called for: " + accessPoints);
? ? }
? ? ...
}
看mWifiTracker.getAccessPoints。

?java框架層

3.2 frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java

/**
* Gets the current list of access points.
*
* <p>This method is can be called on an abitrary thread by clients, but is normally called on
* the UI Thread by the rendering App.
*/
@AnyThread
public List<AccessPoint> getAccessPoints() {
? ? synchronized (mLock) {
? ? ? ? return new ArrayList<>(mInternalAccessPoints);
? ? }
}
接下來的過程最終還是會走到WifiManager.getScanResults,WifiServiceImpl.getScanResults,細節上會有差異。

?
————————————————
版權聲明:本文為CSDN博主「BrighterLi」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/weixin_42093428/article/details/82834234

總結

以上是生活随笔為你收集整理的Wifi模块—源码分析Wifi热点扫描2(Android P)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。