Android U Wi-Fi 打开流程

Android U Wi-Fi 打开流程

WifiManager 它属于WiFi模块对外的接口。所以settings、systemUI都是从这里调用相关WiFi的接口来实现显示相关功能。

下面setWifiEnabled()函数就是开打开关闭WiFi的对外接口,传递Boolean参数即可。调用此方法的应用必须要有android.Manifest.permission#CHANGE_WIFI_STATE相关权限。

//WifiManager.java
    /**
       * Enable or disable Wi-Fi.
       * <p>
       * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
       * permission to toggle wifi.
       *
       * @param enabled {@code true} to enable, {@code false} to disable.
       * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
       *         either already in the requested state, or in progress toward the requested state.
       * @throws  SecurityException if the caller is missing required permissions.
       *
       * @deprecated Starting with Build.VERSION_CODES#Q, applications are not allowed to
       * enable/disable Wi-Fi.
       * <b>Compatibility Note:</b> For applications targeting
       * {@link android.os.Build.VERSION_CODES#Q} or above, this API will always fail and return
       * {@code false}. If apps are targeting an older SDK ({@link android.os.Build.VERSION_CODES#P}
       * or below), they can continue to use this API.
       * <p>
       * Deprecation Exemptions:
       * <ul>
       * <li>Device Owner (DO), Profile Owner (PO) and system apps.
       * </ul>
       *
       * Starting with {@link android.os.Build.VERSION_CODES#TIRAMISU}, DO/COPE may set
       * a user restriction (DISALLOW_CHANGE_WIFI_STATE) to only allow DO/PO to use this API.
       */
      @Deprecated
      public boolean setWifiEnabled(boolean enabled) {
          try {
              return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
          } catch (RemoteException e) {
              throw e.rethrowFromSystemServer();
          }
      }

得知通过aidl 调用的是WifiServiceImpl具体实现。

//WifiServiceImpl.java
       /**
       * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
       * @param enable {@code true} to enable, {@code false} to disable.
       * @return {@code true} if the enable/disable operation was
       *         started or is already in the queue.
       */
      @Override
      public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
          if (enforceChangePermission(packageName) != MODE_ALLOWED) {
              return false;
          }
          int callingUid = Binder.getCallingUid();
          int callingPid = Binder.getCallingPid();
          boolean isPrivileged = isPrivileged(callingPid, callingUid);
          boolean isThirdParty = !isPrivileged
                  && !isDeviceOrProfileOwner(callingUid, packageName)
                  && !mWifiPermissionsUtil.isSystem(packageName, callingUid);
          boolean isTargetSdkLessThanQ = mWifiPermissionsUtil.isTargetSdkLessThan(packageName,
                  Build.VERSION_CODES.Q, callingUid) && !isGuestUser();
          mWifiPermissionsUtil.checkPackage(callingUid, packageName);
          if (isThirdParty && !isTargetSdkLessThanQ) {
              mLog.info("setWifiEnabled not allowed for uid=%").c(callingUid).flush();
              return false;
          }
  //这里主要是判断权限相关的
          // If Satellite mode is enabled, Wifi can not be turned on/off
          if (mSettingsStore.isSatelliteModeOn()) {
              mLog.info("setWifiEnabled not allowed as satellite mode is on.").flush();
              return false;
          }
  
          // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
          if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
              mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
              return false;
          }
  
          // If SoftAp is enabled, only privileged apps are allowed to toggle wifi
          if (!isPrivileged && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {
              mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush();
              return false;
          }
  
          // If user restriction is set, only DO/PO is allowed to toggle wifi
          if (SdkLevel.isAtLeastT() && mUserManager.hasUserRestrictionForUser(
                  UserManager.DISALLOW_CHANGE_WIFI_STATE,
                  UserHandle.getUserHandleForUid(callingUid))
                  && !isDeviceOrProfileOwner(callingUid, packageName)) {
              mLog.err("setWifiEnabled with user restriction: only DO/PO can toggle wifi").flush();
              return false;
          }
  
          // Show a user-confirmation dialog for legacy third-party apps targeting less than Q.
          if (enable && isTargetSdkLessThanQ && isThirdParty
                  && showDialogWhenThirdPartyAppsEnableWifi()) {
              mLog.info("setWifiEnabled must show user confirmation dialog for uid=%").c(callingUid)
                      .flush();
              mWifiThreadRunner.post(() -> {
                  if (mActiveModeWarden.getWifiState()
                          == WIFI_STATE_ENABLED) {
                      // Wi-Fi already enabled; don't need to show dialog.
                      return;
                  }
                  showWifiEnableRequestDialog(callingUid, callingPid, packageName);
              });
              return true;
          }
          //走到了这里
          setWifiEnabledInternal(packageName, enable, callingUid, callingPid, isPrivileged);
          return true;
      }
  
      @AnyThread
      private void setWifiEnabledInternal(String packageName, boolean enable,
              int callingUid, int callingPid, boolean isPrivileged) {
          mLog.info("setWifiEnabled package=% uid=% enable=% isPrivileged=%").c(packageName)
                  .c(callingUid).c(enable).c(isPrivileged).flush();
          long ident = Binder.clearCallingIdentity();
          try {
              //判断飞行模式下是否可以切换WIFI
              if (!mSettingsStore.handleWifiToggled(enable)) {
                  // Nothing to do if wifi cannot be toggled
                  return;
              }
          } finally {
              Binder.restoreCallingIdentity(ident);
          }
          if (enable) {
              // Clear out all outstanding wifi enable request dialogs.
              mWifiThreadRunner.post(() -> {
                  for (int i = 0; i < mWifiEnableRequestDialogHandles.size(); i++) {
                      mWifiEnableRequestDialogHandles.valueAt(i).dismissDialog();
                  }
                  mWifiEnableRequestDialogHandles.clear();
              });
          }
          if (mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)) {
              if (enable) {
                  mWifiThreadRunner.post(
                          () -> mWifiConnectivityManager.setAutoJoinEnabledExternal(true, false));
                  mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON);
              } else {
                  WifiInfo wifiInfo = mActiveModeWarden.getConnectionInfo();
                  mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_OFF,
                          wifiInfo == null ? -1 : wifiInfo.getNetworkId());
              }
          }
          if (!enable) {
              mWifiInjector.getInterfaceConflictManager().reset();
          }
          mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
          mWifiMetrics.reportWifiStateChanged(enable, mWifiInjector.getWakeupController().isUsable(),
                  false);
          //这里开始进行下一步,发送广播
          mActiveModeWarden.wifiToggled(new WorkSource(callingUid, packageName));
          mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED, Process.myTid(),
                  callingUid, callingPid, packageName, enable);
      }
//ActiveModeWarden.java
//这里便是发送广播的地方了,那谁来处理CMD_WIFI_TOGGLED呢?那肯定是DisabledState状态的时候来处理呀。
      /** Wifi has been toggled. */
      public void wifiToggled(WorkSource requestorWs) {
          mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED, requestorWs);
      }
//这里是WifiController创建状态机的地方
          WifiController() {
              super(TAG, mLooper);
              final int threshold = mContext.getResources().getInteger(
                      R.integer.config_wifiConfigurationWifiRunnerThresholdInMs);
              DefaultState defaultState = new DefaultState(threshold);
              mEnabledState = new EnabledState(threshold);
              mDisabledState = new DisabledState(threshold);
              addState(defaultState); {
                  addState(mDisabledState, defaultState);
                  addState(mEnabledState, defaultState);
              }
  
              setLogRecSize(100);
              setLogOnlyTransitions(false);
  
         }
//接收到CMD_WIFI_TOGGLED消息
....
  @Override
              public boolean processMessageFiltered(Message msg) {
                  switch (msg.what) {
                      case CMD_WIFI_TOGGLED:
                      case CMD_SCAN_ALWAYS_MODE_CHANGED:
                          handleStaToggleChangeInDisabledState((WorkSource) msg.obj);
                          break;
....
//transitionTo(mEnabledState);切换状态机到mEnabledState
          private void handleStaToggleChangeInDisabledState(WorkSource requestorWs) {
              if (shouldEnableSta()) {
              //看看这里面干了什么
                  startPrimaryOrScanOnlyClientModeManager(requestorWs);
                  transitionTo(mEnabledState);
              }
          }

 /**
       * Method to enable a new primary client mode manager.
       */
      private boolean startPrimaryOrScanOnlyClientModeManager(WorkSource requestorWs) {
          ActiveModeManager.ClientRole role = getRoleForPrimaryOrScanOnlyClientModeManager();
          if (role == ROLE_CLIENT_PRIMARY) {
              //走到了这里
              return startPrimaryClientModeManager(requestorWs);
          } else if (role == ROLE_CLIENT_SCAN_ONLY) {
              return startScanOnlyClientModeManager(requestorWs);
          } else {
              return false;
          }
      }

      /**
       * Method to enable a new primary client mode manager in connect mode.
       */
      private boolean startPrimaryClientModeManager(WorkSource requestorWs) {
          if (hasPrimaryOrScanOnlyModeManager()) {
              Log.e(TAG, "Unexpected state - primary CMM should not be started when a primary "
                      + "or scan only CMM is already present.");
              if (!mIsMultiplePrimaryBugreportTaken) {
                  mIsMultiplePrimaryBugreportTaken = true;
                  mWifiDiagnostics.takeBugReport("Wi-Fi ActiveModeWarden bugreport",
                          "Trying to start primary mode manager when one already exists.");
              }
              return false;
          }
          Log.d(TAG, "Starting primary ClientModeManager in connect mode");
//创建ClientModeManage对象
          ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
                  new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);
//加入到ConcreteClientModeManager列表集合中
          mClientModeManagers.add(manager);
          mLastPrimaryClientModeManagerRequestorWs = requestorWs;
          return true;
      }
//这里可以看到在WifiInjector里面new   ClientModeManager。
ConcreteClientModeManager manager = mWifiInjector.makeClientModeManager(
                  new ClientListener(), requestorWs, ROLE_CLIENT_PRIMARY, mVerboseLoggingEnabled);

看看ClientModeManager的构造函数

//WifiInjector.java
      /**
       * Create a ClientModeManager
       *
       * @param listener listener for ClientModeManager state changes
       * @return a new instance of ClientModeManager
       */
      public ConcreteClientModeManager makeClientModeManager(
              @NonNull ClientModeManager.Listener<ConcreteClientModeManager> listener,
              @NonNull WorkSource requestorWs,
              @NonNull ActiveModeManager.ClientRole role,
              boolean verboseLoggingEnabled) {
          return new ConcreteClientModeManager(
                  mContext, mWifiHandlerThread.getLooper(), mClock,
                  mWifiNative, listener, mWifiMetrics, mWakeupController,
                  this, mSelfRecovery, mWifiGlobals, mDefaultClientModeManager,
                  mClock.getElapsedSinceBootMillis(), requestorWs, role, mBroadcastQueue,
                  verboseLoggingEnabled);
      }
//调用构造函数发送ClientModeStateMachine.CMD_START广播
ConcreteClientModeManager.java
      ConcreteClientModeManager(
              Context context, @NonNull Looper looper, Clock clock,
              WifiNative wifiNative, @NonNull Listener<ConcreteClientModeManager> listener,
              WifiMetrics wifiMetrics,
              WakeupController wakeupController, WifiInjector wifiInjector,
              SelfRecovery selfRecovery, WifiGlobals wifiGlobals,
              DefaultClientModeManager defaultClientModeManager, long id,
              @NonNull WorkSource requestorWs, @NonNull ClientRole role,
              @NonNull ClientModeManagerBroadcastQueue broadcastQueue,
              boolean verboseLoggingEnabled) {
          mContext = context;
          mClock = clock;
          mWifiNative = wifiNative;
          mModeListener = listener;
          mWifiMetrics = wifiMetrics;
          mWakeupController = wakeupController;
          mWifiInjector = wifiInjector;
          mStateMachine = new ClientModeStateMachine(looper);
          mDeferStopHandler = new DeferStopHandler(looper);
          mSelfRecovery = selfRecovery;
          mWifiGlobals = wifiGlobals;
          mDefaultClientModeManager = defaultClientModeManager;
          mId = id;
          mTargetRoleChangeInfo = new RoleChangeInfo(role, requestorWs, listener);
          mBroadcastQueue = broadcastQueue;
          enableVerboseLogging(verboseLoggingEnabled);
          //send CMD_STATRT
          mStateMachine.sendMessage(ClientModeStateMachine.CMD_START, mTargetRoleChangeInfo);
      }

ClientModeStateMachine.CMD_START广播IdleState处理

                      case CMD_START:
                          // Always start in scan mode first.
                          RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj;
//在这里进行下一步
                          mClientInterfaceName = mWifiNative.setupInterfaceForClientInScanMode(
                                  mWifiNativeInterfaceCallback, roleChangeInfo.requestorWs,
                                  ConcreteClientModeManager.this);
                          if (TextUtils.isEmpty(mClientInterfaceName)) {
                              Log.e(getTag(), "Failed to create ClientInterface. Sit in Idle");
                              takeBugReportInterfaceFailureIfNeeded(
                                      "Wi-Fi BugReport (scan STA interface failure):",
                                      "Failed to create client interface in idle state");
                              mModeListener.onStartFailure(ConcreteClientModeManager.this);
                              break;
                          }
                          mWifiNative.setWifiNativeInterfaceEventCallback(
                                  mWifiNativeInterfaceEventCallback);
                          if (roleChangeInfo.role instanceof ClientConnectivityRole) {
                              sendMessage(CMD_SWITCH_TO_CONNECT_MODE, roleChangeInfo);
                              transitionTo(mStartedState);
                          } else {
                              mScanRoleChangeInfoToSetOnTransition = roleChangeInfo;
                              transitionTo(mScanOnlyModeState);
                          }
                          break;

//WifiNative.java
      /**
       * Setup an interface for client mode (for scan) operations.
       *
       * This method configures an interface in STA mode in the native daemons
       * (wificond, vendor HAL).
       *
       * @param interfaceCallback Associated callback for notifying status changes for the iface.
       * @param requestorWs Requestor worksource.
       * @param concreteClientModeManager ConcreteClientModeManager requesting the interface.
       * @return Returns the name of the allocated interface, will be null on failure.
       */
      public String setupInterfaceForClientInScanMode(
              @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs,
              @NonNull ConcreteClientModeManager concreteClientModeManager) {
          synchronized (mLock) {
//这里调用startHal()
              if (!startHal()) {
                  Log.e(TAG, "Failed to start Hal");
                  mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
                  return null;
              }
              Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
              if (iface == null) {
                  Log.e(TAG, "Failed to allocate new STA iface");
                  return null;
              }
              iface.externalListener = interfaceCallback;
              iface.name = createStaIface(iface, requestorWs, concreteClientModeManager);
              if (TextUtils.isEmpty(iface.name)) {
                  Log.e(TAG, "Failed to create iface in vendor HAL");
                  mIfaceMgr.removeIface(iface.id);
                  mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
                  return null;
              }
              if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
                      new NormalScanEventCallback(iface.name),
                      new PnoScanEventCallback(iface.name))) {
                  Log.e(TAG, "Failed to setup iface in wificond=" + iface.name);
                  teardownInterface(iface.name);
                  mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
                  return null;
              }
              registerInterfaceObserver();
              iface.networkObserver = new NetworkObserverInternal(iface.id);
              if (!registerNetworkObserver(iface.networkObserver)) {
                  Log.e(TAG, "Failed to register network observer for iface=" + iface.name);
                  teardownInterface(iface.name);
                  return null;
              }
              mWifiMonitor.startMonitoring(iface.name);
              // Just to avoid any race conditions with interface state change callbacks,
              // update the interface state before we exit.
              onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
              mWifiVendorHal.enableLinkLayerStats(iface.name);
              Log.i(TAG, "Successfully setup " + iface);
  
              iface.featureSet = getSupportedFeatureSetInternal(iface.name);
              updateSupportedBandForStaInternal(iface);
  
              mWifiVendorHal.enableStaChannelForPeerNetwork(mContext.getResources().getBoolean(
                              R.bool.config_wifiEnableStaIndoorChannelForPeerNetwork),
                      mContext.getResources().getBoolean(
                              R.bool.config_wifiEnableStaDfsChannelForPeerNetwork));
              return iface.name;
          }
      }
   /** Helper method invoked to start supplicant if there were no ifaces */
      private boolean startHal() {
          synchronized (mLock) {
              if (!mIfaceMgr.hasAnyIface()) {
                  if (mWifiVendorHal.isVendorHalSupported()) {
//开启vendor Hal
                      if (!mWifiVendorHal.startVendorHal()) {
                          Log.e(TAG, "Failed to start vendor HAL");
                          return false;
                      }
                     if (SdkLevel.isAtLeastS()) {
                          mWifiVendorHal.setCoexUnsafeChannels(
                                  mCachedCoexUnsafeChannels, mCachedCoexRestrictions);
                      }
                  } else {
                      Log.i(TAG, "Vendor Hal not supported, ignoring start.");
                  }
              }
              registerWificondListenerIfNecessary();
              return true;
          }
      }
//调用供应商的hal
//WifiVendorHal.java 
      /**
       * Bring up the Vendor HAL.
       * @return true on success, false otherwise.
       */
      public boolean startVendorHal() {
          synchronized (sLock) {
              if (!mHalDeviceManager.start()) {//判断调用是否成功
                  mLog.err("Failed to start vendor HAL").flush();
                  return false;
              }
              mLog.info("Vendor Hal started successfully").flush();
              return true;
          }
      }

//调用startWifi()
//HalDeviceManager.java
      /**
       * Attempts to start Wi-Fi. Returns the success (true) or failure (false) or
       * the start operation. Will also dispatch any registered ManagerStatusCallback.onStart() on
       * success.
       */
      public boolean start() {
          return startWifi();
      }


      private boolean startWifi() {
          if (VDBG) Log.d(TAG, "startWifi");
//进行初始化
          initializeInternal();
          synchronized (mLock) {
              int triedCount = 0;
              while (triedCount <= START_HAL_RETRY_TIMES) {
//调用WifiHal.start()
                  int status = mWifiHal.start();
                  if (status == WifiHal.WIFI_STATUS_SUCCESS) {
                      managerStatusListenerDispatch();
                      if (triedCount != 0) {
                          Log.d(TAG, "start IWifi succeeded after trying "
                                   + triedCount + " times");
                      }
                      WifiChipInfo[] wifiChipInfos = getAllChipInfo();
                      if (wifiChipInfos == null) {
                          Log.e(TAG, "Started wifi but could not get current chip info.");
                      }
                      return true;
                  } else if (status == WifiHal.WIFI_STATUS_ERROR_NOT_AVAILABLE) {
                      // Should retry. Hal might still be stopping. the registered event
                      // callback will not be cleared.
                      Log.e(TAG, "Cannot start wifi because unavailable. Retrying...");
                      try {
                          Thread.sleep(START_HAL_RETRY_INTERVAL_MS);
                      } catch (InterruptedException ignore) {
                          // no-op
                      }
                      triedCount++;
                  } else {
                      // Should not retry on other failures.
                      // Will be handled in the onFailure event.
                      Log.e(TAG, "Cannot start IWifi. Status: " + status);
                      return false;
                  }
              }
              Log.e(TAG, "Cannot start IWifi after trying " + triedCount + " times");
              return false;
          }
      }

//启动实际加载WiFi动作的调用,涉及HIDL机制调用
//WifiHal.java
      /**
       * See comments for {@link IWifiHal#start()}
       */
      public @WifiStatusCode int start() {
          return validateAndCall("start", WIFI_STATUS_ERROR_UNKNOWN,
                  () -> mWifiHal.start());
      }
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值