WIFI 打开流程

一 Settings界面

Settings包括了Android原生Settings界面的实现,部分厂商会基于Android-Settings架构定制自己的一些界面,例如XM-Settings、HW-Settings,都会包含在这部分,原生的Settings一般是一个apk文件,命名为Settings.apk,存放在手机/system/priv-app/Settings目录。这部分大多以界面的形式呈现,当我们无法定位到某个界面对于那部分代码时,可以使用如下命令:

adb logcat | grep -iEn "activity|fragment"

二 Wi-Fi打开

2.1 Wi-Fi相关进程
首先,我们打开一台手机设备,看看Wi-Fi打开之后会出现哪些进程:

XXXX:/ # ps -ef | grep -iEn "wifi|supplicant"
482:wifi          1458     1 0 18:19:07 ?     00:00:02 android.hardware.wifi-service
599:wifi          2493     1 0 18:19:11 ?     00:00:00 wificond
608:system        2510     1 0 18:19:11 ?     00:00:00 wifidisplayhalservice
689:wifi          4196     1 0 18:19:19 ?     00:00:00 wpa_supplicant -O/data/vendor/wifi/wpa/sockets -puse_p2p_group_interface=1 -dd -g@android:wpa_wlan0

可以看到有四个进程:
1.android.hardware.wifi-service
他是wifi hal服务,负责wifiservice和wpa_supplicant、hostapd之间的通信进程,它是一个由C++编码实现的守护进程,其源码路径一般都是在hardware/interfaces/wifi/aidl/default下边,一般会有一个rc文件来启动这个进程。
2.2.wificond
他是wifi的一个守护进程,主要实现wifi的扫描功能;其代码结构如下:
在这里插入图片描述
3.wifidisplayhalservice
Wi-Fi P2P的进程;
4.wpa_supplicant
Wi-Fi的守护进程;

2.2 Wi-Fi service启动

wifiService是在系统启动时被systemServer进程拉起来;SystemServer.java文件中包含了wifiService的拉起过程:

private static final String WIFI_SERVICE_CLASS =
            "com.android.server.wifi.WifiService";
    private static final String WIFI_SCANNING_SERVICE_CLASS =
            "com.android.server.wifi.scanner.WifiScanningService";
    //systemServer进程启动 
    private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
    ...
               if (context.getPackageManager().hasSystemFeature(
                    PackageManager.FEATURE_WIFI)) {
                // Wifi Service must be started first for wifi-related services.
                t.traceBegin("StartWifi");
                mSystemServiceManager.startServiceFromJar(
                        WIFI_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
                t.traceEnd();
                t.traceBegin("StartWifiScanning");
                mSystemServiceManager.startServiceFromJar(
                        WIFI_SCANNING_SERVICE_CLASS, WIFI_APEX_SERVICE_JAR_PATH);
                t.traceEnd();
            }

在wifiService被拉起来之后,会new一个wifi注册器WifiInjector和WifServiceImpl;
在这里插入图片描述
注意:onStart方法是在对象初始化时执行,目的是将wifiService服务注册到ServiceManager;
(1)Wi-Fi注射器的作用是将framework层Wi-Fi相关的服务全部拉起来,这个时候不同的服务在各自的构造函数中做一些初始化的动作。
在这里插入图片描述
(2)创建WifiServiceImpl对象,这个类相当关键,他是wifiService的大管家,所有用户端的请求都会被他分发给不同的服务去处理;在Android S/T/U版本中新增了两个类:
clientModeImpl:它的作用类似于老版本中的WifiStateMachine,主要处理连接、注网以及客户端请求的事件和回调处理。

ActiveModeWarden官方是这样解释的,大家在后续自己阅读源码过程中细细体会,里边应用了Android状态机

2.3 Wi-Fi启动流程

1.应用调用WifiManager.setWifiEnabled()

public boolean setWifiEnabled(boolean enabled) {
        try {
            return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

2.WifiManager通过AIDL机制调用WifiSericeImpl.setWifiEnabled()


/packages/modules/Wifi/service/java/com/android/server/wifi/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;
        }
        // 如果以上全部通过,将调用真正的wifi打开动作
        setWifiEnabledInternal(packageName, enable, callingUid, callingPid, isPrivileged);
        return true;
    
 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 {
            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);
    }

3.开始进入到ActiveModeWarden类,调用wifiToggled方法;

/packages/modules/Wifi/service/java/com/android/server/wifi/ActiveModeWarden.java
mActiveModeWarden.wifiToggled(new WorkSource(callingUid, packageName));
    /** Wifi has been toggled. */
    public void wifiToggled(WorkSource requestorWs) {
        mWifiController.sendMessage(WifiController.CMD_WIFI_TOGGLED, requestorWs);
    }

这里发送了一个消息CMD_WIFI_TOGGLED,WifiController是一个内部类,在ActiveModeWarden构造函数中进行初始化,之后WifiController的构造函数中会调用WifiNative.initialize函数,其目的是初始化wifi hal服务。ActiveModeWarden服务也是在wifi server初始化过程中通过构造函数初始化。WifiController这里第一个接触状态机,其关系如下:
在这里插入图片描述
对于消息处理仍然采用之前的机制,父状态机优先处理,

 private class IdleState extends RunnerState {
                switch (message.what) {
                    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.setupInterfaceClientInScanMode方法;

 public String setupInterfaceForClientInScanMode(
            @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs,
            @NonNull ConcreteClientModeManager concreteClientModeManager) {
        synchronized (mLock) {
        //加载wlan驱动
            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;
            //创建wlan网口
            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;
            }
            //创建STA接口 
            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();
            //监听wlan网口up/down状态 
            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;
            }
            //监听wpa_supplicant状态 
            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;
        }
    }

其调用栈是:

wifi.cpp -->startInternal()

wifi.cpp–>initializeModeControllerAndLegacyHal()

WifiModeController.cpp–>initialize()

DriverTool.cpp–>LoadDiver()

/frameworks/opt/net/wifi/libwifi_hal/driver_tool.cpp
 bool DriverTool::LoadDriver() {
  return ::wifi_load_driver() == 0;
}
int wifi_load_driver() {
#ifdef WIFI_DRIVER_MODULE_PATH
  if (is_wifi_driver_loaded()) {
    return 0;
  }

  if (insmod(DRIVER_MODULE_PATH, DRIVER_MODULE_ARG) < 0) return -1;
#endif

#ifdef WIFI_DRIVER_STATE_CTRL_PARAM
  if (is_wifi_driver_loaded()) {
    return 0;
  }

  if (wifi_change_driver_state(WIFI_DRIVER_STATE_ON) < 0) {
#ifdef WIFI_DRIVER_MODULE_PATH
    PLOG(WARNING) << "Driver unloading, err='fail to change driver state'";
    if (rmmod(DRIVER_MODULE_NAME) == 0) {
      PLOG(DEBUG) << "Driver unloaded";
    } else {
      // Set driver prop to "ok", expect HL to restart Wi-Fi.
      PLOG(DEBUG) << "Driver unload failed! set driver prop to 'ok'.";
      property_set(DRIVER_PROP_NAME, "ok");
    }
#endif
    return -1;
  }
#endif
  is_driver_loaded = true;
  return 0;
}

这里有几个注意点
1.命令如何挂载wlan驱动
insmod 驱动路径
2.驱动挂载之后会更新一个系统属性
wlan.driver.status OK
3.wlan驱动挂载后会更新设备节点
/sys/class/net/wlan0

到此第一部分CMD_START消息处理完成;开始处理第二个消息,即消息CMD_SWITCH_TO_CONNECT_MODE;

5.处理消息CMD_SWITCH_TO_CONNECT_MODE,这个消息的主要作用就是启动wpa_supplicant守护进程;

注意在这里wifi开启状态被更新为Enabling状态;
framework与wpa_supplicant进程通信是通过AIDL机制,ISupplicant是一个hal服务,其目录结构如下:
在这里插入图片描述
asInterface 这个方法将触发wpa_supplicant进程,进入到wpa_supplicant的main函数中;
在一系列调用之后,完成switchClientInterfaceToConnectivityMode方法的调用,回到状态机ConnectModeState中,更新wifi状态为Enabled状态

6.ClientModeImpl开始准备L2、L3层服务启动
在这里插入图片描述
在这里插入图片描述
至此,wifi服务全部启动,如果触发连接,将会将客户端连接请求交给ClientModeImpl进行消息的处理和时间响应。

### 回答1: Android 11的WiFi打开函数调用流程图如下: 1. 点击设备的“设置”按钮,进入系统设置界面。 2. 在设置界面中找到“网络和互联网”的选项,点击进入。 3. 在网络和互联网界面中,找到并点击“WiFi”选项。 4. 进入WiFi设置界面后,点击“开启WiFi”按钮。 5. 设备调用系统的WiFi管理模块,开始执行WiFi打开流程。 6. WiFi管理模块首先检查设备的WiFi芯片状态,如果芯片已经关闭,则需要先打开WiFi芯片。 7. 如果WiFi芯片已经打开,则WiFi管理模块开始搜索可用的WiFi网络。 8. 当找到可用的WiFi网络时,WiFi管理模块会尝试连接到该网络。 9. 连接到WiFi网络后,设备会获取该网络的IP地址和其他网络相关信息。 10. 设备将WiFi连接状态设置为已连接,并通知系统和应用程序。 11. 如果WiFi连接失败或者没有可用的WiFi网络,WiFi管理模块将会关闭WiFi芯片并返回WiFi打开失败的信息。 以上就是Android 11的WiFi打开函数调用流程图。在实际执行中,可能还会有一些其他细节和错误处理逻辑,但总体而言,这个流程可以帮助用户打开设备的WiFi功能并连接到可用的WiFi网络。 ### 回答2: Android 11中的WiFi打开函数调用流程图如下: 1. 首先,应用程序通过调用WiFiManager类的getSystemService()方法获取系统的WiFi服务实例。 2. 接下来,应用程序通过调用WiFiManager类的setWifiEnabled()方法来打开WiFi功能。 3. WiFiManager类会将该请求传递给系统服务,即WifiService类。 4. WifiService类会通过调用WifiController类的方法来处理WiFi打开请求。 5. WifiController类会检查当前设备的权限和状态,以确定是否允许打开WiFi。 6. 如果设备具有足够的权限并且当前设备处于正确状态,则WifiController类会继续处理打开WiFi请求。 7. WifiController类会与驱动程序进行通信,以控制硬件设备的操作,从而打开WiFi。 8. 一旦WiFi硬件设备成功打开WifiController类会通知WifiService类。 9. WifiService类随后会通知应用程序,指示WiFi已成功打开。 10. 最后,应用程序可以进一步使用WiFi功能,如连接到可用的WiFi网络。 请注意,Android 11中的WiFi打开函数调用流程可能会因设备和系统定制而有所不同。上述流程图仅为概述,具体实现可能会有所差异。 ### 回答3: Android 11中的Wi-Fi打开函数调用流程图如下: 1. 应用程序调用Wi-Fi Manager类的`setWifiEnabled(true)`方法,用于打开Wi-Fi功能。 2. Wi-Fi Manager类将此请求发送给系统服务。 3. 系统服务接收到请求后,检查当前设备是否具有足够的权限来打开Wi-Fi。如果权限不足,服务将拒绝请求,并向应用程序返回相应的错误代码。 4. 如果应用程序具有足够的权限,系统服务将检查与Wi-Fi硬件驱动程序的通信是否正常。如果存在通信问题,服务将返回相应的错误代码。 5. 如果无任何问题,系统服务将向Wi-Fi硬件驱动程序发送打开Wi-Fi的指令。 6. Wi-Fi硬件驱动程序接收到指令后,控制Wi-Fi芯片打开相应的电路和无线射频器。 7. 一旦Wi-Fi硬件处于打开状态,驱动程序将返回成功的消息给系统服务。 8. 系统服务收到成功消息后,将其传递给Wi-Fi Manager类。 9. Wi-Fi Manager类会更新其内部状态,表示Wi-Fi已成功打开。 10. Wi-Fi Manager类将成功的消息返回给应用程序,通知其Wi-Fi已成功打开。 11. 应用程序可以通过检查Wi-Fi Manager类的状态来确认Wi-Fi是否已打开。 总的来说,Android 11中的Wi-Fi打开函数调用流程主要涉及应用程序调用Wi-Fi Manager类的方法,将请求传递给系统服务,然后由系统服务与Wi-Fi硬件驱动程序进行通信以打开Wi-Fi。最后,成功的消息将传递回应用程序,并更新Wi-Fi Manager类的内部状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值