1.WiFiManager
packages\modules\Wifi\framework\java\android\net\wifi\WifiManager.java startScan
@Deprecated public boolean startScan() { return startScan(null); } /** @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public boolean startScan(WorkSource workSource) { try { String packageName = mContext.getOpPackageName(); String attributionTag = mContext.getAttributionTag(); return mService.startScan(packageName, attributionTag); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
2.IWifiManager
packages\modules\Wifi\framework\java\android\net\wifi\WifiManager.aidl
@UnsupportedAppUsage IWifiManager mService;
3.BaseWifiService实现WifiManager接口
public class BaseWifiService extends IWifiManager.Stub {
packages\modules\Wifi\service\java\com\android\server\wifi\BaseWifiService.java
4.WifiServiceImpl实现具体逻辑
packages\modules\Wifi\service\java\com\android\server\wifi\WifiServiceImpl.java
@Override public boolean startScan(String packageName, String featureId) { if (enforceChangePermission(packageName) != MODE_ALLOWED) { return false; } int callingUid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); mLog.info("startScan uid=%").c(callingUid).flush(); synchronized (this) { if (mInIdleMode) { // Need to send an immediate scan result broadcast in case the // caller is waiting for a result .. // TODO: investigate if the logic to cancel scans when idle can move to // WifiScanningServiceImpl. This will 1 - clean up WifiServiceImpl and 2 - // avoid plumbing an awkward path to report a cancelled/failed scan. This will // be sent directly until b/31398592 is fixed. sendFailedScanBroadcast(); mScanPending = true; return false; } } try { mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid, null); Boolean scanSuccess = mWifiThreadRunner.call(() -> mScanRequestProxy.startScan(callingUid, packageName), null); if (scanSuccess == null) { sendFailedScanBroadcast(); return false; } if (!scanSuccess) { Log.e(TAG, "Failed to start scan"); return false; } } catch (SecurityException e) { Log.w(TAG, "Permission violation - startScan not allowed for" + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e); return false; } finally { Binder.restoreCallingIdentity(ident); } return true; }
enforceChangePermission会核查是否获取了android.Manifest.permission.CHANGE_WIFI_STATE权限
@CheckResult private int enforceChangePermission(String callingPackage) { mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); if (checkNetworkSettingsPermission(Binder.getCallingPid(), Binder.getCallingUid())) { return MODE_ALLOWED; } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, "WifiService"); return mAppOps.noteOp( AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Binder.getCallingUid(), callingPackage); }
5.WifiPermissionsUtil的enforceCanAccessScanResults会继续检查权限
packages\modules\Wifi\service\java\com\android\server\wifi\util\WifiPermissionsUtil.java
public void enforceCanAccessScanResults(String pkgName, @Nullable String featureId, int uid, @Nullable String message) throws SecurityException { checkPackage(uid, pkgName); // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_MANAGED_PROVISIONING, // NETWORK_STACK & MAINLINE_NETWORK_STACK, RADIO_SCAN_WITHOUT_LOCATION are granted a bypass. if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid) || checkNetworkManagedProvisioningPermission(uid) || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid) || checkScanWithoutLocationPermission(uid)) { return; } // Location mode must be enabled if (!isLocationModeEnabled()) { if (mVerboseLoggingEnabled) { Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " + "location is disabled"); } // Location mode is disabled, scan results cannot be returned throw new SecurityException("Location mode is disabled for the device"); } // Check if the calling Uid has CAN_READ_PEER_MAC_ADDRESS permission. boolean canCallingUidAccessLocation = checkCallerHasPeersMacAddressPermission(uid); // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to // location information. boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId, uid, /* coarseForTargetSdkLessThanQ */ true, message); // If neither caller or app has location access, there is no need to check // any other permissions. Deny access to scan results. if (!canCallingUidAccessLocation && !canAppPackageUseLocation) { if (mVerboseLoggingEnabled) { Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " + "canCallingUidAccessLocation=" + canCallingUidAccessLocation + ", canAppPackageUseLocation=" + canAppPackageUseLocation); } throw new SecurityException("UID " + uid + " has no location permission"); } // Check if Wifi Scan request is an operation allowed for this App. if (!isScanAllowedbyApps(pkgName, featureId, uid)) { if (mVerboseLoggingEnabled) { Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " + "doesn't have app-op " + AppOpsManager.OPSTR_WIFI_SCAN); } throw new SecurityException("UID " + uid + " has no wifi scan permission"); } // If the User or profile is current, permission is granted // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. boolean isCurrentProfile = isCurrentProfile(uid); if (!isCurrentProfile && !checkInteractAcrossUsersFull(uid)) { if (mVerboseLoggingEnabled) { Log.v(TAG, "enforceCanAccessScanResults(pkg=" + pkgName + ", uid=" + uid + "): " + "isCurrentProfile=" + isCurrentProfile + ", checkInteractAcrossUsersFull=" + checkInteractAcrossUsersFull(uid)); } throw new SecurityException("UID " + uid + " profile not permitted"); } }
6.调用 \packages\modules\Wifi\service\java\com\android\server\wifi\ScanRequestProxy.java 的startScan
/** * Initiate a wifi scan. * * @param callingUid The uid initiating the wifi scan. Blame will be given to this uid. * @return true if the scan request was placed or a scan is already ongoing, false otherwise. */ public boolean startScan(int callingUid, String packageName) { if (!mScanningEnabled || !retrieveWifiScannerIfNecessary()) { Log.e(TAG, "Failed to retrieve wifiscanner"); sendScanResultFailureBroadcastToPackage(packageName); return false; } boolean fromSettingsOrSetupWizard = mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid) || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(callingUid); // Check and throttle scan request unless, // a) App has either NETWORK_SETTINGS or NETWORK_SETUP_WIZARD permission. // b) Throttling has been disabled by user. int packageImportance = getPackageImportance(callingUid, packageName); if (!fromSettingsOrSetupWizard && mThrottleEnabled && shouldScanRequestBeThrottledForApp(callingUid, packageName, packageImportance)) { Log.i(TAG, "Scan request from " + packageName + " throttled"); sendScanResultFailureBroadcastToPackage(packageName); return false; } // Create a worksource using the caller's UID. WorkSource workSource = new WorkSource(callingUid, packageName); mWifiMetrics.getScanMetrics().setWorkSource(workSource); mWifiMetrics.getScanMetrics().setImportance(packageImportance); // Create the scan settings. WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings(); // Scan requests from apps with network settings will be of high accuracy type. if (fromSettingsOrSetupWizard) { settings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY; } else { if (SdkLevel.isAtLeastS()) { // since the scan request is from a normal app, do not scan all 6Ghz channels. settings.set6GhzPscOnlyEnabled(true); } } settings.band = WifiScanner.WIFI_BAND_ALL; settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT; if (mScanningForHiddenNetworksEnabled) { settings.hiddenNetworks.clear(); // retrieve the list of hidden network SSIDs from saved network to scan for, if enabled. settings.hiddenNetworks.addAll(mWifiConfigManager.retrieveHiddenNetworkList()); // retrieve the list of hidden network SSIDs from Network suggestion to scan for. settings.hiddenNetworks.addAll( mWifiInjector.getWifiNetworkSuggestionsManager().retrieveHiddenNetworkList()); } mWifiScanner.startScan(settings, new HandlerExecutor(mHandler), new ScanRequestProxyScanListener(), workSource); return true; }
7.调用WifiScanner的startScan
packages\modules\Wifi\framework\java\android\net\wifi\WifiScanner.java
@RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void startScan(ScanSettings settings, @Nullable @CallbackExecutor Executor executor, ScanListener listener, WorkSource workSource) { Objects.requireNonNull(listener, "listener cannot be null"); int key = addListener(listener, executor); if (key == INVALID_KEY) return; validateChannel(); Bundle scanParams = new Bundle(); scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings); scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource); scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName()); scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag()); mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams); }
8.mAsyncChannel是AsyncChannel类型的变量,内部通过Messager实现进程间通信
frameworks\base\core\java\com\android\internal\util\AsyncChannel.java
@UnsupportedAppUsage public void sendMessage(Message msg) { msg.replyTo = mSrcMessenger; try { mDstMessenger.send(msg); } catch (RemoteException e) { replyDisconnected(STATUS_SEND_UNSUCCESSFUL); } }
/** Messenger for destination */ private Messenger mDstMessenger;
9.WifiScanningServiceImpl实现进程间通信,处理响应的message
packages\modules\Wifi\service\java\com\android\server\wifi\scanner\WifiScanningServiceImpl.java
@Override public Messenger getMessenger() { if (mClientHandler != null) { mLog.trace("getMessenger() uid=%").c(Binder.getCallingUid()).flush(); return new Messenger(mClientHandler); } loge("WifiScanningServiceImpl trying to get messenger w/o initialization"); return null; }
消息处理的handler是ClientHandler mClientHandler
ClientHandler 是WifiScanningServiceImpl的内部类
case WifiScanner.CMD_START_SINGLE_SCAN: case WifiScanner.CMD_STOP_SINGLE_SCAN: mSingleScanStateMachine.sendMessage(Message.obtain(msg)); break;
然后转入WifiSingleScanStateMachine类中,WifiSingleScanStateMachine是WifiScanningServiceImpl的内部类
WifiSingleScanStateMachine有DefaultState ,用来处理消息
private final DefaultState mDefaultState = new DefaultState();
case WifiScanner.CMD_START_SINGLE_SCAN: handleScanStartMessage(ci, msg);
/** * Helper method to handle the scan start message. */ private void handleScanStartMessage(ClientInfo ci, Message msg) { int handler = msg.arg2; Bundle scanParams = (Bundle) msg.obj; if (scanParams == null) { logCallback("singleScanInvalidRequest", ci, handler, "null params"); replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); return; } ScanSettings scanSettings = null; WorkSource workSource = null; try { scanSettings = scanParams.getParcelable( WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY); workSource = scanParams.getParcelable( WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY); } catch (BadParcelableException e) { Log.wtf(TAG, "Failed to get parcelable params", e); logCallback("singleScanInvalidRequest", ci, handler, "bad parcel params"); replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad parcel params"); return; } if (validateScanRequest(ci, handler, scanSettings)) { if (getCurrentState() == mDefaultState && !scanSettings.ignoreLocationSettings) { // Reject regular scan requests if scanning is disabled. replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available"); return; } mWifiMetrics.incrementOneshotScanCount(); if ((scanSettings.band & WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY) != 0) { mWifiMetrics.incrementOneshotScanWithDfsCount(); } logScanRequest("addSingleScanRequest", ci, handler, workSource, scanSettings, null); replySucceeded(msg); if (scanSettings.ignoreLocationSettings) { // Inform wifi manager that an emergency scan is in progress (regardless of // whether scanning is currently enabled or not). This ensures that // the wifi chip remains on for the duration of this scan. mWifiManager.setEmergencyScanRequestInProgress(true); } if (getCurrentState() == mScanningState) { // If there is an active scan that will fulfill the scan request then // mark this request as an active scan, otherwise mark it pending. if (activeScanSatisfies(scanSettings)) { mActiveScans.addRequest(ci, handler, workSource, scanSettings); } else { mPendingScans.addRequest(ci, handler, workSource, scanSettings); } } else if (getCurrentState() == mIdleState) { // If were not currently scanning then try to start a scan. Otherwise // this scan will be scheduled when transitioning back to IdleState // after finishing the current scan. mPendingScans.addRequest(ci, handler, workSource, scanSettings); tryToStartNewScan(); } else if (getCurrentState() == mDefaultState) { // If scanning is disabled and the request is for emergency purposes // (checked above), add to pending list. this scan will be scheduled when // transitioning to IdleState when wifi manager enables scanning as a part of // processing WifiManager.setEmergencyScanRequestInProgress(true) mPendingScans.addRequest(ci, handler, workSource, scanSettings); } } else { logCallback("singleScanInvalidRequest", ci, handler, "bad request"); replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); mWifiMetrics.incrementScanReturnEntry( WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1); } }
void tryToStartNewScan() { if (mPendingScans.size() == 0) { // no pending requests return; } mChannelHelper.updateChannels(); // TODO move merging logic to a scheduler WifiNative.ScanSettings settings = new WifiNative.ScanSettings(); settings.num_buckets = 1; WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); bucketSettings.bucket = 0; bucketSettings.period_ms = 0; bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; ChannelCollection channels = mChannelHelper.createChannelCollection(); List<WifiNative.HiddenNetwork> hiddenNetworkList = new ArrayList<>(); for (RequestInfo<ScanSettings> entry : mPendingScans) { settings.scanType = mergeScanTypes(settings.scanType, entry.settings.type); settings.enable6GhzRnr = mergeRnrSetting(settings.enable6GhzRnr, entry.settings); channels.addChannels(entry.settings); for (ScanSettings.HiddenNetwork srcNetwork : entry.settings.hiddenNetworks) { WifiNative.HiddenNetwork hiddenNetwork = new WifiNative.HiddenNetwork(); hiddenNetwork.ssid = srcNetwork.ssid; hiddenNetworkList.add(hiddenNetwork); } if ((entry.settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) { bucketSettings.report_events |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT; } if (entry.clientInfo != null) { mWifiMetrics.getScanMetrics().setClientUid(entry.clientInfo.mUid); } mWifiMetrics.getScanMetrics().setWorkSource(entry.workSource); } if (hiddenNetworkList.size() > 0) { settings.hiddenNetworks = new WifiNative.HiddenNetwork[hiddenNetworkList.size()]; int numHiddenNetworks = 0; for (WifiNative.HiddenNetwork hiddenNetwork : hiddenNetworkList) { settings.hiddenNetworks[numHiddenNetworks++] = hiddenNetwork; } } channels.fillBucketSettings(bucketSettings, Integer.MAX_VALUE); settings.buckets = new WifiNative.BucketSettings[] {bucketSettings}; if (mScannerImplsTracker.startSingleScan(settings)) { mWifiMetrics.getScanMetrics().logScanStarted( WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE); // store the active scan settings mActiveScanSettings = settings; // swap pending and active scan requests RequestList<ScanSettings> tmp = mActiveScans; mActiveScans = mPendingScans; mPendingScans = tmp; // make sure that the pending list is clear mPendingScans.clear(); transitionTo(mScanningState); } else { mWifiMetrics.incrementScanReturnEntry( WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size()); mWifiMetrics.getScanMetrics().logScanFailedToStart( WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE); // notify and cancel failed scans sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED, "Failed to start single scan"); } }
调用ScannerImplsTracker的startSingleScan方法 ,ScannerImplsTracker是WifiScanningServiceImpl的内部类
/** * Triggers a new scan on all the available scanner impls. * @return true if the scan succeeded on any of the impl, false otherwise. */ public boolean startSingleScan(WifiNative.ScanSettings scanSettings) { mStatusPerImpl.clear(); boolean anySuccess = false; for (Map.Entry<String, WifiScannerImpl> entry : mScannerImpls.entrySet()) { String ifaceName = entry.getKey(); WifiScannerImpl impl = entry.getValue(); boolean success = impl.startSingleScan( scanSettings, new ScanEventHandler(ifaceName)); if (!success) { Log.e(TAG, "Failed to start single scan on " + ifaceName); mStatusPerImpl.put(ifaceName, STATUS_FAILED); continue; } mStatusPerImpl.put(ifaceName, STATUS_PENDING); anySuccess = true; } return anySuccess; }
调用 WifiScannerImpl 的startSingleScan方法
Wifi/service/java/com/android/server/wifi/scanner/HalWifiScannerImpl.java:38:public class HalWifiScannerImpl extends WifiScannerImpl implements Handler.Callback { Wifi/service/java/com/android/server/wifi/scanner/WificondScannerImpl.java:52:public class WificondScannerImpl extends WifiScannerImpl implements Handler.Callback {
packages\modules\Wifi\service\java\com\android\server\wifi\scanner\HalWifiScannerImpl.java
public boolean startSingleScan(WifiNative.ScanSettings settings, WifiNative.ScanEventHandler eventHandler) { return mWificondScannerDelegate.startSingleScan(settings, eventHandler); }
@Override public boolean startSingleScan(WifiNative.ScanSettings settings, WifiNative.ScanEventHandler eventHandler) { if (eventHandler == null || settings == null) { Log.w(TAG, "Invalid arguments for startSingleScan: settings=" + settings + ",eventHandler=" + eventHandler); return false; } synchronized (mSettingsLock) { if (mLastScanSettings != null) { Log.w(TAG, "A single scan is already running"); return false; } ChannelCollection allFreqs = mChannelHelper.createChannelCollection(); boolean reportFullResults = false; for (int i = 0; i < settings.num_buckets; ++i) { WifiNative.BucketSettings bucketSettings = settings.buckets[i]; if ((bucketSettings.report_events & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0) { reportFullResults = true; } allFreqs.addChannels(bucketSettings); } List<String> hiddenNetworkSSIDSet = new ArrayList<>(); if (settings.hiddenNetworks != null) { int numHiddenNetworks = Math.min(settings.hiddenNetworks.length, MAX_HIDDEN_NETWORK_IDS_PER_SCAN); for (int i = 0; i < numHiddenNetworks; i++) { hiddenNetworkSSIDSet.add(settings.hiddenNetworks[i].ssid); } } mLastScanSettings = new LastScanSettings( mClock.getElapsedSinceBootNanos(), reportFullResults, allFreqs, eventHandler); boolean success = false; Set<Integer> freqs = Collections.emptySet(); if (!allFreqs.isEmpty()) { freqs = allFreqs.getScanFreqs(); success = mWifiNative.scan( getIfaceName(), settings.scanType, freqs, hiddenNetworkSSIDSet, settings.enable6GhzRnr); if (!success) { Log.e(TAG, "Failed to start scan, freqs=" + freqs); } } else { // There is a scan request but no available channels could be scanned for. // We regard it as a scan failure in this case. Log.e(TAG, "Failed to start scan because there is no available channel to scan"); } if (success) { if (DBG) { Log.d(TAG, "Starting wifi scan for freqs=" + freqs + " on iface " + getIfaceName()); } mScanTimeoutListener = new AlarmManager.OnAlarmListener() { @Override public void onAlarm() { handleScanTimeout(); } }; mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, mClock.getElapsedSinceBootMillis() + SCAN_TIMEOUT_MS, TIMEOUT_ALARM_TAG, mScanTimeoutListener, mEventHandler); } else { // indicate scan failure async mEventHandler.post(() -> reportScanFailure()); } return true; } }
调用WifiNative的scan方法
packages\modules\Wifi\service\java\com\android\server\wifi\WifiNative.java
public boolean scan( @NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs, List<String> hiddenNetworkSSIDs, boolean enable6GhzRnr) { List<byte[]> hiddenNetworkSsidsArrays = new ArrayList<>(); for (String hiddenNetworkSsid : hiddenNetworkSSIDs) { try { hiddenNetworkSsidsArrays.add( NativeUtil.byteArrayFromArrayList( NativeUtil.decodeSsid(hiddenNetworkSsid))); } catch (IllegalArgumentException e) { Log.e(TAG, "Illegal argument " + hiddenNetworkSsid, e); continue; } } // enable6GhzRnr is a new parameter first introduced in Android S. if (SdkLevel.isAtLeastS()) { Bundle extraScanningParams = new Bundle(); extraScanningParams.putBoolean(WifiNl80211Manager.SCANNING_PARAM_ENABLE_6GHZ_RNR, enable6GhzRnr); return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays, extraScanningParams); } else { return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays); } }
标签:java,scan,uid,settings,WiFi,扫描,new,return,Android From: https://www.cnblogs.com/wanglongjiang/p/17653965.html