Android Q wifi开启流程

Framework中,wifistatemachine拆散为ModeStateMachine,softAp相关从wifistatemachine迁移至softApStateMachine确保wifi的各个模式独立

Framework启动:
WifiManager::setWifiEnabled
  ->WifiServiceImpl::WifiManager::setWifiEnabled
    ->WifiController::StaDisabledState::processMessage(CMD_WIFI_TOGGLED)
    ->WifiController::StaEnabledState::Enter()
      ->ActiveModeWarden::enterClientMode()
        ->ActiveModeWarden::ModeStateMachine::checkForAndHandleModeChange(CMD_START_CLIENT_MODE)
      ->ClientModeActiveState::Enter()
        ->ClientModeManager::Start()
          ->ClientModeManager::ClientModeStateMachine::processMessage(CMD_START)
            ->WifiNative::setupInterfaceForClientInConnectivityManager

HAL启动承接framework启动:
StartHal()
  ->StartVendorHal()
    ->HalDeviceManager::startWifi()
  HIDL -> Native:
      ->wifi::startInternal()
        ->initializeModeControllerAndLegacyHal
          ->ModeController::LoadDriver()
            ->wifi_hal_common::wifi_load_driver()
              ->insmod(wlan.ko)
          ->wifi_legacy_hal::initialize()
            ->initHalFuncTableWithStubs()
            ->init_wifi_vendor_hal_func_table()

Driver启动承接HAL启动: 高通的驱动集体过程就不贴出来了
wlan_module_init() 注册wlan驱动
一般来讲,以上过程后,会触发probe操作。探测总线成功后,回调probe函数指针。

这时wifi驱动算是加载成功, 驱动总线接口配置, 开启电源管理, 初始化mac地址, firmware实在这里加载并解析mac地址的,接口注册为网络设备wlan0, 开启P2P接口,p2p0

wlan_probe()

Supplicant启动承接framework启动:驱动开启了,supplicant才有netlink连接可以建立
StartSupplicant()
  ->startAndWaitForSupplicantConnection()
    ->StartDaemon() 启动wpa_supplicant
  HIDL -> Native
      ->Main() -> 解析参数
        ->wpa_supplicant_init()
          ->eap_register_methods() 注册eap状态机
          ->eloop_init() 创建loop,用于实现supplicant中的异步化
          ->wpas_notify_supplicant_initialized() 初始化与上层对应的喊出表,用于返回底层信息
        ->wpa_supplicant_add_iface()
          ->wpa_supplicant_init_iface()
            ->wpas_init_driver()
              ->wpa_drv_init()
                ->wpa_driver_nl80211_init() 初始化netlink连接
          ->wpa_supplicant_driver_init()配置mac,扫描参数,supplicant状态机初始化
          ->wpas_wps_init() wps初始化,配置相关认证方法
          ->wpa_supplicant_init_eapol() 初始化eap认证参数
          ->wifi_display_init() 开启 wifidisplay功能

<think> 我们讨论的是如何让Android设备忘记一个已保存的WiFi热点。这涉及到使用WifiManager来移除已配置的网络。 步骤: 1. 获取WifiManager实例。 2. 获取已配置的网络列表。 3. 根据SSID(网络名称)找到对应的网络配置。 4. 调用removeNetwork(int networkId)方法移除该网络。 5. 调用saveConfiguration()保存更改。 6. 最后,可能需要重新连接到其他网络或者更新列表。 注意:在Android 10及以上,应用需要有定位权限(如果定位是开启的)才能获取WiFi列表,并且需要动态请求位置权限。 下面是一个完整的示例代码,包括必要的权限和动态权限请求(针对Android 6.0及以上)。 首先,在AndroidManifest.xml中添加权限: ```xml <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/> <!-- 对于Android 10及以上,如果应用的目标SDK版本>=29,还需要访问位置权限来获取WiFi列表 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> ``` 然后,在Activity中实现忘记热点的功能: </think> ### Android 忘记 WiFi 热点实现方案 #### 完整代码实现 ```java public class WifiForgetUtil { private static final String TAG = "WifiForgetUtil"; /** * 忘记指定SSID的WiFi热点 * @param context 上下文对象 * @param ssid 要忘记的热点SSID * @return 操作是否成功 */ public static boolean forgetWifiNetwork(Context context, String ssid) { // 步骤1: 获取WifiManager实例 WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); if (wifiManager == null) { Log.e(TAG, "WifiManager is not available"); return false; } // 步骤2: 检查必要权限 if (!hasRequiredPermissions(context)) { Log.e(TAG, "Missing required permissions"); return false; } // 步骤3: 获取所有配置的网络 List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks(); if (configs == null) { Log.e(TAG, "No configured networks found"); return false; } boolean found = false; String formattedSsid = "\"" + ssid + "\""; // 步骤4: 遍历查找匹配的网络配置 for (WifiConfiguration config : configs) { if (config.SSID != null && config.SSID.equals(formattedSsid)) { Log.d(TAG, "Found network to remove: " + config.SSID + ", ID: " + config.networkId); // 步骤5: 移除网络 boolean removed = wifiManager.removeNetwork(config.networkId); if (!removed) { Log.w(TAG, "Failed to remove network: " + config.networkId); continue; } found = true; Log.d(TAG, "Successfully removed network: " + config.networkId); } } // 步骤6: 保存配置 boolean saved = wifiManager.saveConfiguration(); Log.d(TAG, "Configuration saved: " + saved); return found && saved; } /** * 忘记所有已保存的WiFi热点 * @param context 上下文对象 * @return 操作是否成功 */ public static boolean forgetAllWifiNetworks(Context context) { WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); if (wifiManager == null) return false; if (!hasRequiredPermissions(context)) { Log.e(TAG, "Missing required permissions"); return false; } List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks(); if (configs == null || configs.isEmpty()) { Log.d(TAG, "No networks to remove"); return true; } boolean allRemoved = true; for (WifiConfiguration config : configs) { boolean removed = wifiManager.removeNetwork(config.networkId); if (!removed) { Log.w(TAG, "Failed to remove network: " + config.networkId); allRemoved = false; } } if (allRemoved) { Log.d(TAG, "All networks removed successfully"); } boolean saved = wifiManager.saveConfiguration(); Log.d(TAG, "Configuration saved: " + saved); return allRemoved && saved; } /** * 检查所需权限是否已授予 */ private static boolean hasRequiredPermissions(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android 10+ 需要位置权限 return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; } else { return true; } } /** * 请求忘记WiFi所需的权限 */ public static void requestRequiredPermissions(Activity activity, int requestCode) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, requestCode); } } } ``` #### 使用示例 ```java // 在Activity中忘记特定热点 public class WifiSettingsActivity extends AppCompatActivity { private static final int PERMISSION_REQUEST_CODE = 100; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_wifi_settings); Button forgetBtn = findViewById(R.id.btn_forget); forgetBtn.setOnClickListener(v -> { // 检查权限 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { // 请求位置权限 WifiForgetUtil.requestRequiredPermissions(this, PERMISSION_REQUEST_CODE); } else { // 已有权限,直接执行 forgetWifiNetwork("MyHomeWiFi"); } }); } private void forgetWifiNetwork(String ssid) { boolean success = WifiForgetUtil.forgetWifiNetwork(this, ssid); if (success) { Toast.makeText(this, "Successfully forgot network: " + ssid, Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Failed to forget network", Toast.LENGTH_SHORT).show(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_REQUEST_CODE) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { forgetWifiNetwork("MyHomeWiFi"); } else { Toast.makeText(this, "Permission denied. Cannot forget WiFi network", Toast.LENGTH_SHORT).show(); } } } } ``` #### 关键点解释 1. **权限处理**: ```java private static boolean hasRequiredPermissions(Context context) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; } else { return true; } } ``` - Android 10(API 29)及以上需要位置权限才能访问WiFi配置 - Android 9及以下只需标准WiFi权限 2. **SSID格式处理**: ```java String formattedSsid = "\"" + ssid + "\""; ``` - 系统存储SSID时默认添加双引号 - 必须格式化SSID才能正确匹配 3. **网络移除流程**: ```java boolean removed = wifiManager.removeNetwork(config.networkId); boolean saved = wifiManager.saveConfiguration(); ``` - `removeNetwork()` 移除指定网络配置 - `saveConfiguration()` 永久保存更改 4. **批量移除实现**: ```java public static boolean forgetAllWifiNetworks(Context context) { // 遍历所有网络配置并移除 } ``` - 提供一键移除所有保存网络的功能 - 返回操作是否全部成功 #### 权限声明 (AndroidManifest.xml) ```xml <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <!-- Android 10+ 需要位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> ``` #### Android版本兼容性处理 | Android版本 | 所需权限 | 特殊处理 | |------------|----------|---------| | Android 5-8 | ACCESS_WIFI_STATE<br>CHANGE_WIFI_STATE | 无 | | Android 9 | ACCESS_WIFI_STATE<br>CHANGE_WIFI_STATE | 需开启位置服务 | | Android 10+ | ACCESS_FINE_LOCATION<br>ACCESS_WIFI_STATE<br>CHANGE_WIFI_STATE | 动态请求位置权限 | #### 常见问题解决方案 1. **权限问题导致失败**: - 确保在AndroidManifest.xml声明所有必要权限 - Android 10+ 需动态请求位置权限 - 引导用户开启设备位置服务(Android 9) 2. **无法找到指定SSID**: ```java // 尝试不同SSID格式 String[] possibleFormats = { "\"" + ssid + "\"", // 标准格式 ssid, // 无引号格式 "\\\"" + ssid + "\\\"", // 转义格式 ssid.replace("\"", "") // 清理引号 }; ``` - 系统可能以不同格式存储SSID - 尝试多种格式匹配 3. **移除后热点重新出现**: ```java // 禁用网络自动重连 wifiManager.disableNetwork(config.networkId); wifiManager.removeNetwork(config.networkId); ``` - 先禁用网络再移除 - 防止系统自动重新添加热点 #### 高级功能:移除热点后断开连接 ```java public static boolean forgetAndDisconnect(Context context, String ssid) { WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); if (wifiManager == null) return false; // 获取当前连接信息 WifiInfo connectionInfo = wifiManager.getConnectionInfo(); // 如果当前连接的是要移除的热点 if (connectionInfo != null && connectionInfo.getSSID() != null && connectionInfo.getSSID().equals("\"" + ssid + "\"")) { // 先断开连接 wifiManager.disconnect(); Log.d(TAG, "Disconnected from current network"); } // 执行移除操作 return forgetWifiNetwork(context, ssid); } ``` #### 测试验证 ```java // 单元测试示例 @Test public void testForgetWifiNetwork() { Context context = ApplicationProvider.getApplicationContext(); String testSsid = "TestNetwork"; // 添加测试网络 addTestNetwork(context, testSsid); // 执行忘记操作 boolean result = WifiForgetUtil.forgetWifiNetwork(context, testSsid); // 验证结果 assertTrue(result); assertFalse(isNetworkConfigured(context, testSsid)); } private void addTestNetwork(Context context, String ssid) { WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); WifiConfiguration config = new WifiConfiguration(); config.SSID = "\"" + ssid + "\""; config.preSharedKey = "\"password\""; wifiManager.addNetwork(config); wifiManager.saveConfiguration(); } ``` --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值