wifisetting.java_Wifi 笔记 | 启动流程

csd:csdn_of_coder/article/details/51541094

aosp: Android O

Android网络各个模式中,Wifi应该是目前最常用的一种网络方式了;下面就简单介绍下Android中Wifi的启动流程。

当我在Setting菜单里点击打开Wifi时,调用的入口函数是WifiManager::setWifiEnabled(boolean enabled):

用户可以通过systemUi和设置里的WiFi开关打开WiFi,这时候会调用到wifi framework的相关接口,继而再继续往下启用具体的硬件完成WiFi启动流程,这里只对应用到framework层有些简单的了解,本篇也主要注重framework这一块

一、WIFI启动总体流程

WiFi打开流程还是从设置的WiFi开关开始梳理吧,不考虑打开飞行模式后打开WiFi的情况

766347d49596

总体流程

二、WIFI启动分步详解:

2.1 设置启动WiFi

设置这边说到底其实就是监控WiFi开关的变化,然后根据开关走对应的逻辑处理。

两个比较重要的类:

WifiSettings:设置中wifi主界面所对应的代码

WifiEnabler:设置中负责wifi开关打开和关闭事件处理的类

2.1.1 WifiSettings

//packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.java

private WifiEnabler createWifiEnabler() {

final SettingsActivity activity = (SettingsActivity) getActivity();

return new WifiEnabler(activity, new SwitchBarController(activity.getSwitchBar()),

mMetricsFeatureProvider);

}

//packages/apps/Settings/src/com/android/settings/widget/SwitchBarController.java

public class SwitchBarController extends SwitchWidgetController implements

}

2.1.2 WifiEnabler

//packages/apps/Settings/src/com/android/settings/wifi/WifiEnabler.java

WifiEnabler(Context context, SwitchWidgetController switchWidget,

}

//省略N多代码

{

mWifiManager.setWifiEnabled(isChecked)) {

}

}

2.1.3 总结:

看到这里其实发现应用层打开和关闭WiFi就是调用了下WifiManager的setWifiEabled(boolean)接口即可。

2.2 WiFi framework

2.2.1 WifiManager的setWifiEabled接口

//framework/base/wifi/java/android/net/wifi/WifiManager.java

public boolean setWifiEnabled(boolean enabled) {

try {

return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);

} catch (RemoteException e) {

throw e.rethrowFromSystemServer();

}

}

2.2.2 WifiService的setWifiEnabled

IWifiManager mService;

public WifiManager(Context context, IWifiManager service, Looper looper) {

mContext = context;

mService = service;

mLooper = looper;

mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;

}

mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

2.2.3 注册服务

///framework/base/core/java/android/app/SystemServiceRegistry.java

registerService(Context.WIFI_SERVICE, WifiManager.class,

new CachedServiceFetcher() {

@Override

public WifiManager createService(ContextImpl ctx) throws ServiceNotFoundException {

IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SERVICE);

IWifiManager service = IWifiManager.Stub.asInterface(b);

return new WifiManager(ctx.getOuterContext(), service,

ConnectivityThread.getInstanceLooper());

}});

IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SERVICE);

2.2.4 WifiService

SystemServer启动WifiService

private static final String WIFI_SERVICE_CLASS ="com.android.server.wifi.WifiService";

mSystemServiceManager.startService(WIFI_SERVICE_CLASS);

WifiService 是接口类,WifiServiceImpl 是实现类

public final class WifiService extends SystemService {

private static final String TAG = "WifiService";

final WifiServiceImpl mImpl;

public WifiService(Context context) {

super(context);

mImpl = new WifiServiceImpl(context, new WifiInjector(context), new WifiAsyncChannel(TAG));

}

@Override

public void onStart() {

Log.i(TAG, "Registering " + Context.WIFI_SERVICE);

publishBinderService(Context.WIFI_SERVICE, mImpl);

}

2.3 Service的WiFi启动流程

public class WifiServiceImpl extends IWifiManager.Stub {

/**

* 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)

throws RemoteException {

enforceChangePermission();

Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()

+ ", uid=" + Binder.getCallingUid() + ", package=" + packageName);

mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)

.c(Binder.getCallingUid()).c(enable).flush();

boolean isFromSettings = checkNetworkSettingsPermission(

Binder.getCallingPid(), Binder.getCallingUid());

// If Airplane mode is enabled, only Settings is allowed to toggle Wifi

if (mSettingsStore.isAirplaneModeOn() && !isFromSettings) {

mLog.info("setWifiEnabled in Airplane mode: only Settings can enable wifi").flush();

return false;

}

// If SoftAp is enabled, only Settings is allowed to toggle wifi

boolean apEnabled =

mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;

if (apEnabled && !isFromSettings) {

mLog.info("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();

return false;

}

/*

* Caller might not have WRITE_SECURE_SETTINGS,

* only CHANGE_WIFI_STATE is enforced

*/

long ident = Binder.clearCallingIdentity();

try {

if (! mSettingsStore.handleWifiToggled(enable)) {

// Nothing to do if wifi cannot be toggled

return true;

}

} finally {

Binder.restoreCallingIdentity(ident);

}

if (mPermissionReviewRequired) {

final int wiFiEnabledState = getWifiEnabledState();

if (enable) {

if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING

|| wiFiEnabledState == WifiManager.WIFI_STATE_DISABLED) {

if (startConsentUi(packageName, Binder.getCallingUid(),

WifiManager.ACTION_REQUEST_ENABLE)) {

return true;

}

}

} else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING

|| wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) {

if (startConsentUi(packageName, Binder.getCallingUid(),

WifiManager.ACTION_REQUEST_DISABLE)) {

return true;

}

}

}

mWifiController.sendMessage(CMD_WIFI_TOGGLED);

return true;

}

2.3.1 WifiController 中的WIFI

service会调用WifiController来处理WIFI的启动,WifiController是一个状态机,异步处理WIF启动 过程

mWifiController.sendMessage(CMD_WIFI_TOGGLED);

mSettingsStore.handleWifiToggled(enable)设置一下SettingsProvider中存储的WIFI_ON的值

public synchronized boolean handleWifiToggled(boolean wifiEnabled) {

// Can Wi-Fi be toggled in airplane mode ?

if (mAirplaneModeOn && !isAirplaneToggleable()) {

return false;

}

if (wifiEnabled) {

if (mAirplaneModeOn) {

persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);

} else {

persistWifiState(WIFI_ENABLED);

}

} else {

// When wifi state is disabled, we do not care

// if airplane mode is on or not. The scenario of

// wifi being disabled due to airplane mode being turned on

// is handled handleAirplaneModeToggled()

persistWifiState(WIFI_DISABLED);

}

return true;

}

WifiServiceImpl在走到WifiController之前有提及修改了一下SettingsProvider,其实也顺带改了一下WifiSettingsStore的mPersistWifiState值,用来标记wifi状态。

persistWifiState(WIFI_ENABLED);

public synchronized boolean isWifiToggleEnabled() {

if (!mCheckSavedStateAtBoot) {

mCheckSavedStateAtBoot = true;

if (testAndClearWifiSavedState()) return true;

}

if (mAirplaneModeOn) {

return mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE;

} else {

return mPersistWifiState != WIFI_DISABLED;

}

}

private boolean doDeferEnable(Message msg) {

long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp;

if (delaySoFar >= mReEnableDelayMillis) {

return false;

}

log("WifiController msg " + msg + " deferred for " +

(mReEnableDelayMillis - delaySoFar) + "ms");

// need to defer this action.

Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);

deferredMsg.obj = Message.obtain(msg);

deferredMsg.arg1 = ++mDeferredEnableSerialNumber;

sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS);

return true;

}

mReEnableDelayMillis = mFacade.getLongSetting(mContext,

Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS);

2.3.2 WifiStateMachine 状态机

mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);

mWifiStateMachine.setSupplicantRunning(true);

mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);

mWifiStateMachine.setHighPerfModeEnabled(false);

在状态处理中会发送:CMD_START_SUPPLICANT 启动协议栈的认证机制wpa_supplicant

接收到该消息进行的关键操作:

mWifiNative.enableSupplicant()

mWifiMonitor.startMonitoring(mInterfaceName, true);

切换到SupplicantStartingState状态

2.3.4 协议栈

public boolean enableSupplicant() {

return mWificondControl.enableSupplicant();

}

public synchronized void startMonitoring(String iface, boolean isStaIface) {

if (ensureConnectedLocked()) {

setMonitoring(iface, true);

broadcastSupplicantConnectionEvent(iface);

} else {

boolean originalMonitoring = isMonitoring(iface);

setMonitoring(iface, true);

broadcastSupplicantDisconnectionEvent(iface);

setMonitoring(iface, originalMonitoring);

Log.e(TAG, "startMonitoring(" + iface + ") failed!");

}

}

2.3.5 WifiNative中的Supplicant

private void setSuspendOptimizationsNative(int reason, boolean enabled) {

if (mVerboseLoggingEnabled) {

log("setSuspendOptimizationsNative: " + reason + " " + enabled

+ " -want " + mUserWantsSuspendOpt.get()

+ " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()

+ " - " + Thread.currentThread().getStackTrace()[3].getMethodName()

+ " - " + Thread.currentThread().getStackTrace()[4].getMethodName()

+ " - " + Thread.currentThread().getStackTrace()[5].getMethodName());

}

//mWifiNative.setSuspendOptimizations(enabled);

if (enabled) {

mSuspendOptNeedsDisabled &= ~reason;

/* None of dhcp, screen or highperf need it disabled and user wants it enabled */

if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt.get()) {

if (mVerboseLoggingEnabled) {

log("setSuspendOptimizationsNative do it " + reason + " " + enabled

+ " stack:" + Thread.currentThread().getStackTrace()[2].getMethodName()

+ " - " + Thread.currentThread().getStackTrace()[3].getMethodName()

+ " - " + Thread.currentThread().getStackTrace()[4].getMethodName()

+ " - " + Thread.currentThread().getStackTrace()[5].getMethodName());

}

mWifiNative.setSuspendOptimizations(true);

}

} else {

mSuspendOptNeedsDisabled |= reason;

mWifiNative.setSuspendOptimizations(false);

}

}

完~~~

整理 | 力卉编程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/441348.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【CodeForces - 589F】Gourmet and Banquet (贪心,思维,二分)

题干: A gourmet came into the banquet hall, where the cooks suggested n dishes for guests. The gourmet knows the schedule: when each of the dishes will be served. For i-th of the dishes he knows two integer moments in time ai and bi (in second…

java 调用动态链接库_JAVA技巧:JNative调用动态链接库问题(SOS)

动态链接库的方法如下:__declspec(dllexport) ret __stdcall rLachTran(const char *pc_trancode,const char *pc_clicode,const char *pc_orgcode,const char *pc_ttycode,const int i_brandid,const char *pc_reqstamp,const int i_reqseqno,const char *pc_svrip…

SPFA算法模板

简单的一个模板吧&#xff0c;留个底。如果要判负环的话&#xff0c;需要加一个cnt数组记录入队次数就可以了。 void spfa(int st) {memset(dis,INF,sizeof dis);queue<int> q;q.push(st);dis[st]0;vis[st]1;while(!q.empty()) {int cur q.front();q.pop();vis[cur]0;i…

js和php能生成一样的随机数_JavaScript_JS生成某个范围的随机数【四种情况详解】,前言: JS没有现成的函数,能 - phpStudy...

JS生成某个范围的随机数【四种情况详解】前言&#xff1a;JS没有现成的函数&#xff0c;能够直接生成指定范围的随机数。但是它有个函数&#xff1a;Math.random() 这个函数可以生成 [0,1) 的一个随机数。利用它&#xff0c;我们就可以生成指定范围内的随机数。而涉及范围的话…

【POJ - 3347 】Kadj Squares (计算几何,思维 或 扫描线)

题干&#xff1a; In this problem, you are given a sequence S1, S2, ..., Sn of squares of different sizes. The sides of the squares are integer numbers. We locate the squares on the positive x-y quarter of the plane, such that their sides make 45 degrees w…

按钮开关java代码,Android自定义实现开关按钮代码

我们在应用中经常看到一些选择开关状态的配置文件&#xff0c;做项目的时候用的是android的Switch控件&#xff0c;但是感觉好丑的样子子个人认为还是自定义的比较好&#xff0c;先上个效果图&#xff1a;实现过程&#xff1a;1.准备开关不同状态的两张图片放入drawable中。2.x…

java创建的zip没写入权限,java中的zip创建错误

我正在使用ZipOutputStream,FileOutputStream和FileInputStream.首先我创建了一个包含一个文件的文件夹它成功创建了.然后我尝试创建zip文件.动态地,它首次正确创建文件,但第二次,第三次在打开文件时出错.Error: zip [path/././file.zip] Cannot open The process cannot acces…

【qduoj - 夏季学期创新题】最长公共子串(水题暴力枚举,不是LCS啊)

题干&#xff1a; 描述 编写一个程序&#xff0c;求两个字符串的最长公共子串。输出两个字符串的长度&#xff0c;输出他们的最长公共子串及子串长度。如果有多个最长公共子串请输出在第一个字符串中先出现的那一个。 特别注意公共子串中可能包含有空格&#xff0c;但不计回车…

向量合并 matlab,MATLAB追加向量

如果有两个行向量 r1 和 r2 这两个行向量中各有 n 和 m 个元素&#xff0c;现在创建行向量 r 并将n和m个元素都放在行向量 r 中&#xff0c;通过附加这些载体&#xff0c;编写&#xff1a;r [r1,r2]通过追加这两个向量&#xff0c;向量r2的&#xff0c;也可以建立一个矩阵R&am…

*【CodeForces - 202C 】Clear Symmetry (思维,找规律,特判)

题干&#xff1a; Consider some square matrix A with side n consisting of zeros and ones. There are nrows numbered from 1 to n from top to bottom and n columns numbered from 1 to n from left to right in this matrix. Well denote the element of the matrix wh…

matlab将模型解封装,模型保护 - MATLAB Simulink - MathWorks 中国

当您要与第三方共享模型而又不能泄露知识产权时&#xff0c;请对模型进行保护。Test your protected model by comparing it to the original model.Attach a digital signature to your protected model.Files to include in the protected model package.Specify a post-proc…

*【CodeForces - 768B】Code For 1 (分治策略,模拟二分思想,模拟线段树思想)

题干&#xff1a; Jon fought bravely to rescue the wildlings who were attacked by the white-walkers at Hardhome. On his arrival, Sam tells him that he wants to go to Oldtown to train at the Citadel to become a maester, so he can return and take the decease…

matlab 自适应噪声对消,基于Matlab的RLS自适应语音噪声对消系统的设计与实现

基于Matlab 的R LS 自适应语音噪声对消系统的设计与实现①肖 哲(湖南工业大学科技学院, 湖南株洲 412008)摘 要:自适应信号处理的理论和技术经过40多年的发展和完善,已逐渐成为人们常用的语音去噪技术.而Matlab 的出现又为其提供了更为方便快捷的方法来对语音信号进行消噪处…

【qduoj - 142】 多重背包(0-1背包的另类处理,dp)

题干&#xff1a; ycb的ACM进阶之路 Description ycb是个天资聪颖的孩子&#xff0c;他的梦想是成为世界上最伟大的ACMer。为此&#xff0c;他想拜附近最有威望的dalao为师。dalao为了判断他的资质&#xff0c;给他出了一个难题。dalao把他带到一个到处都是题的oj里对他说&am…

python数字类型怎么学,python的数字类型学习之数据类型

1、在python中&#xff0c;数字并不是一个真正的对象类型&#xff0c;而是一组类似类型的分类。它支持通常的数字类型&#xff0c;还能够可以通过常量直接创建数字&#xff0c;还可以处理数字表达式。2、数字常量&#xff1a;(1)整数和浮点数常量(2)16进制、8进制、2进制常量(3…

贪心算法 -- 最小延迟调度

转自&#xff1a;https://blog.csdn.net/bqw18744018044/article/details/80285414 总结&#xff1a; 首先&#xff0c;证明贪心的时候交换论证是万能的&#xff01;其次&#xff0c;这一点如果要满足&#xff0c;也就是&#xff0c;如果你要用交换论证法&#xff0c;那么首先…

php成行排列,一个php实现的生成排列的算法

function perm($s, $n, $index){if($n 0){return ;}else{$nIndex count($index); //可用的字符串下标$res array();foreach($index as $i > $v){$tmp $index;unset($tmp[$i]); //去掉当前的前缀/* 调试信息&#xff0c;便于理解echo "len $n , cur $i , index:\n&q…

【CodeForces - 1051C 】Vasya and Multisets (模拟)

题干&#xff1a; Vasya has a multiset ss consisting of nn integer numbers. Vasya calls some number xxnice if it appears in the multiset exactly once. For example, multiset {1,1,2,3,3,3,4}{1,1,2,3,3,3,4} contains nice numbers 22 and 44. Vasya wants to spl…

apache2+支持php7,Ubuntu14.04下配置PHP7.0+Apache2+Mysql5.7

Apache步骤一&#xff1a;安装apacheronyaoubuntu:~$ sudo apt install apache2安装好后&#xff0c;在浏览器上输入localhost(服务器端&#xff0c;请输入你的IP地址)&#xff0c;回车就会看到&#xff1a;PHP7.0步骤二&#xff1a;Ubuntu14.04下的默认源是PHP5.0&#xff0c;…

php怎么添加验证码,PHP添加验证码以及使用

现在很多页面在使用表单提交时&#xff0c;都会使用到验证码的使用、如何制做一个验证码呢&#xff1f;这里有一个用PHP的方法 以及代码1、首先在php.ini 配置文件里面把GD库打开 // 在php.ini里面找到 extensionphp_gd2.dll 把前面的分号删去。2、代码&#xff1a;<?php …