Android13 Wifi Scan流程梳理

搞openharmony的公司黄掉了,做回android了,惨!
Android13 wifi模块移动到/package/modules中了

├── WifiDialog
├── apex
├── framework
└── service
通过aidl暴露给上端的api
调用对应的service
app
framework
service

以扫描流程为例:
IWifiManager.aidl
这里是提供给上层的api:

    boolean startScan(String packageName, String featureId);

WifiServiceImpl是IWifiManager这个binder的服务端:
WifiServiceImpl.java

    public boolean startScan(String packageName, String featureId) {
        if (enforceChangePermission(packageName) != MODE_ALLOWED) {
            return false;
        }
        int callingUid = Binder.getCallingUid();
        mWifiPermissionsUtil.checkPackage(callingUid, packageName);

        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;
    }

ScanRequestProxy.java

    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(false));
            // retrieve the list of hidden network SSIDs from Network suggestion to scan for.
            settings.hiddenNetworks.addAll(
                    mWifiInjector.getWifiNetworkSuggestionsManager()
                    .retrieveHiddenNetworkList(false));
        }
        mWifiScanner.startScan(settings, new HandlerExecutor(mHandler),
                new ScanRequestProxyScanListener(), workSource);
        return true;
    }

WifiScaner.java

    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);
    }

AsyncChannel是一个作为Handler之间的通道,我们看这个asyncchannel定义的地方:

    public WifiScanner(@NonNull Context context, @NonNull IWifiScanner service,
            @NonNull Looper looper) {
        mContext = context;
        mService = service;

        Messenger messenger = null;
        try {
            messenger = mService.getMessenger(); // 获取WifiScanningServiceImpl中包含mClientHandler的Messenger
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        if (messenger == null) {
            throw new IllegalStateException("getMessenger() returned null!  This is invalid.");
        }

        mAsyncChannel = new AsyncChannel();

        mInternalHandler = new ServiceHandler(looper);
        mAsyncChannel.connectSync(mContext, mInternalHandler, messenger);
        // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message
        // synchronously, which causes WifiScanningService to receive the wrong replyTo value.
        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
    }

WifiScanner在初始化的时候,绑定了WifiScanningServiceImpl中的包含mClientHandle的messenger,发message到clienthanle,然后由WifiSingleScanStateMachine状态机处理
WifiScanningServiceImpl.java

                case WifiScanner.CMD_START_SINGLE_SCAN:
                case WifiScanner.CMD_STOP_SINGLE_SCAN:
                    mSingleScanStateMachine.sendMessage(Message.obtain(msg));
                    break;
        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);
            }
        }

后续一直调用到tracker的startsingleScan

            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;
            }

顺着impl.startSingleScan一路找,最终在WifiNl80211Manager.java

    public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
            @SuppressLint("NullableCollection") @Nullable Set<Integer> freqs,
            @SuppressLint("NullableCollection") @Nullable List<byte[]> hiddenNetworkSSIDs,
            @SuppressLint("NullableCollection") @Nullable Bundle extraScanningParams) {
        IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
        if (scannerImpl == null) {
            Log.e(TAG, "No valid wificond scanner interface handler for iface=" + ifaceName);
            return false;
        }
        SingleScanSettings settings = new SingleScanSettings();
        try {
            settings.scanType = getScanType(scanType);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Invalid scan type ", e);
            return false;
        }
        settings.channelSettings  = new ArrayList<>();
        settings.hiddenNetworks  = new ArrayList<>();
        if (extraScanningParams != null) {
            settings.enable6GhzRnr = extraScanningParams.getBoolean(SCANNING_PARAM_ENABLE_6GHZ_RNR);
        }

        if (freqs != null) {
            for (Integer freq : freqs) {
                ChannelSettings channel = new ChannelSettings();
                channel.frequency = freq;
                settings.channelSettings.add(channel);
            }
        }
        if (hiddenNetworkSSIDs != null) {
            for (byte[] ssid : hiddenNetworkSSIDs) {
                HiddenNetwork network = new HiddenNetwork();
                network.ssid = ssid;

                // settings.hiddenNetworks is expected to be very small, so this shouldn't cause
                // any performance issues.
                if (!settings.hiddenNetworks.contains(network)) {
                    settings.hiddenNetworks.add(network);
                }
            }
        }

        try {
            return scannerImpl.scan(settings);
        } catch (RemoteException e1) {
            Log.e(TAG, "Failed to request scan due to remote exception");
        }
        return false;
    }

scannerImpl.scan(settings)这里通过aidl调用c++的服务,这里的流程也不复杂,就是打包,然后通过netlink将NL80211_CMD_TRIGGER_SCAN发送到内核

bool ScanUtils::Scan(uint32_t interface_index,
                     bool request_random_mac,
                     const vector<vector<uint8_t>>& ssids,
                     const vector<uint32_t>& freqs,
                     int* error_code) {
  NL80211Packet trigger_scan(
      netlink_manager_->GetFamilyId(),
      NL80211_CMD_TRIGGER_SCAN, // event
      netlink_manager_->GetSequenceNumber(),
      getpid());
  // If we do not use NLM_F_ACK, we only receive a unicast repsonse
  // when there is an error. If everything is good, scan results notification
  // will only be sent through multicast.
  // If NLM_F_ACK is set, there will always be an unicast repsonse, either an
  // ERROR or an ACK message. The handler will always be called and removed by
  // NetlinkManager.
  trigger_scan.AddFlag(NLM_F_ACK);
  NL80211Attr<uint32_t> if_index_attr(NL80211_ATTR_IFINDEX, interface_index);
 
 
  NL80211NestedAttr ssids_attr(NL80211_ATTR_SCAN_SSIDS);
  for (size_t i = 0; i < ssids.size(); i++) {
    ssids_attr.AddAttribute(NL80211Attr<vector<uint8_t>>(i, ssids[i]));
  }
  NL80211NestedAttr freqs_attr(NL80211_ATTR_SCAN_FREQUENCIES);
  for (size_t i = 0; i < freqs.size(); i++) {
    freqs_attr.AddAttribute(NL80211Attr<uint32_t>(i, freqs[i]));
  }
 
 
  trigger_scan.AddAttribute(if_index_attr);
  trigger_scan.AddAttribute(ssids_attr);
  // An absence of NL80211_ATTR_SCAN_FREQUENCIES attribue informs kernel to
  // scan all supported frequencies.
  if (!freqs.empty()) {
    trigger_scan.AddAttribute(freqs_attr);
  }
 
 
  if (request_random_mac) {
    trigger_scan.AddAttribute(
        NL80211Attr<uint32_t>(NL80211_ATTR_SCAN_FLAGS,
                              NL80211_SCAN_FLAG_RANDOM_ADDR));
  }
  // We are receiving an ERROR/ACK message instead of the actual
  // scan results here, so it is OK to expect a timely response because
  // kernel is supposed to send the ERROR/ACK back before the scan starts.
  vector<unique_ptr<const NL80211Packet>> response;
  if (!netlink_manager_->SendMessageAndGetAckOrError(trigger_scan,
                                                     error_code)) {
    // Logging is done inside |SendMessageAndGetAckOrError|.
    return false;
  }
  if (*error_code != 0) {
    LOG(ERROR) << "NL80211_CMD_TRIGGER_SCAN failed: " << strerror(*error_code);
    return false;
  }
  return true;
}
bool NetlinkManager::SendMessageInternal(const NL80211Packet& packet, int fd,
    InterceptedSocket nl_destination) {
  const vector<uint8_t>& data = packet.GetConstData();
  struct sockaddr_nl sa = nl_destination;

  ssize_t bytes_sent = TEMP_FAILURE_RETRY(
      sendto(fd, data.data(), data.size(), 0, reinterpret_cast<struct sockaddr*>(&sa), sizeof(sa))
      );
  if (bytes_sent == -1) {
    PLOG(ERROR) << "Failed to send netlink message";
    CHECK(!nlinterceptor::isEnabled()) << "Interceptor died, restarting wificond...";
    return false;
  }
  return true;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值