前言:最近又重新拿起来WiFi模块,从WiFi 各个流程梳理开始复习一下。

参考博客:https://blog.csdn.net/csdn_of_coder/article/details/51541094

(里面也不少framework和WiFi的文章,我得过一遍,很对口)

aosp: Android O

1.wifi启动流程简介

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

2.WiFi启动流程梳理

我之前是负责设置模块的,systemUi代码虽然看过,但是不是很熟,所以WiFi打开流程还是从设置的WiFi开关开始梳理吧,不考虑打开飞行模式后打开WiFi的情况=-=

2.1 设置启动WiFi

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

两个比较重要的类:

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

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

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

    /*** @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard)*/private WifiEnabler createWifiEnabler() {final SettingsActivity activity = (SettingsActivity) getActivity();return new WifiEnabler(activity, new SwitchBarController(activity.getSwitchBar()),mMetricsFeatureProvider);}

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

public class SwitchBarController extends SwitchWidgetController implementsSwitchBar.OnSwitchChangeListener {private final SwitchBar mSwitchBar;public SwitchBarController(SwitchBar switchBar) {mSwitchBar = switchBar;}
...
    @Overridepublic void startListening() {mSwitchBar.addOnSwitchChangeListener(this);}
...@Overridepublic void onSwitchChanged(Switch switchView, boolean isChecked) {if (mListener != null) {mListener.onSwitchToggled(isChecked);}}

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

    @VisibleForTestingWifiEnabler(Context context, SwitchWidgetController switchWidget,MetricsFeatureProvider metricsFeatureProvider,ConnectivityManagerWrapper connectivityManagerWrapper) {mContext = context;mSwitchWidget = switchWidget;mSwitchWidget.setListener(this);mMetricsFeatureProvider = metricsFeatureProvider;mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);mConnectivityManager = connectivityManagerWrapper;mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);// The order matters! We really should not depend on this. :(mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);setupSwitchController();}
mSwitchWidget.setListener(this);mMetricsFeatureProvider = metricsFeatureProvider;mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);mConnectivityManager = connectivityManagerWrapper;mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);// The order matters! We really should not depend on this. :(mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);setupSwitchController();}
    public void setupSwitchController() {final int state = mWifiManager.getWifiState();handleWifiStateChanged(state);if (!mListeningToOnSwitchChange) {mSwitchWidget.startListening();mListeningToOnSwitchChange = true;}mSwitchWidget.setupView();}
@Overridepublic boolean onSwitchToggled(boolean isChecked) {//Do nothing if called as a result of a state machine eventif (mStateMachineEvent) {return true;}// Show toast message if Wi-Fi is not allowed in airplane modeif (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();// Reset switch to off. No infinite check/listenenr loop.mSwitchWidget.setChecked(false);return false;}// Disable tethering if enabling Wifiif (mayDisableTethering(isChecked)) {mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);}if (isChecked) {mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_ON);} else {// Log if user was connected at the time of switching off.mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_OFF,mConnected.get());}if (!mWifiManager.setWifiEnabled(isChecked)) {// ErrormSwitchWidget.setEnabled(true);Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();}return true;}mWifiManager.setWifiEnabled(isChecked)) {// ErrormSwitchWidget.setEnabled(true);Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();}return true;}

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

2.2 WiFi framework

看下WifiManager的setWifiEabled(boolean)接口

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

    /*** Enable or disable Wi-Fi.** Note: This method will return false if wifi cannot be enabled (e.g., an incompatible mode* where the user has enabled tethering or Airplane Mode).** Applications need to have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}* permission to toggle wifi. Callers without the permissions will trigger a* {@link java.lang.SecurityException}.** @param enabled {@code true} to enable, {@code false} to disable.* @return {@code true} if the operation succeeds (or if the existing state*         is the same as the requested state). False if wifi cannot be toggled on/off when the*         request is made.*/public boolean setWifiEnabled(boolean enabled) {try {return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

2.2.1 WifiService是什么

而mService是啥呢

    IWifiManager mService;/*** Create a new WifiManager instance.* Applications will almost always want to use* {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve* the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.* @param context the application context* @param service the Binder interface* @hide - hide this because it takes in a parameter of type IWifiManager, which* is a system private class.*/public WifiManager(Context context, IWifiManager service, Looper looper) {mContext = context;mService = service;mLooper = looper;mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;}

应用层的WifiManager都是这么来的

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

那真正的WifiManager实例是谁来new出来的呢?

有这么一个类:

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

        registerService(Context.WIFI_SERVICE, WifiManager.class,new CachedServiceFetcher<WifiManager>() {@Overridepublic 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());}});

它有个静态代码块,大致如下,负责创建各种manager实例

final class SystemServiceRegistry {
...// Not instantiable.private SystemServiceRegistry() { }static {registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,new CachedServiceFetcher<AccessibilityManager>() {@Overridepublic AccessibilityManager createService(ContextImpl ctx) {return AccessibilityManager.getInstance(ctx);}});registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,new CachedServiceFetcher<CaptioningManager>() {@Overridepublic CaptioningManager createService(ContextImpl ctx) {return new CaptioningManager(ctx);}});registerService(Context.ACCOUNT_SERVICE, AccountManager.class,new CachedServiceFetcher<AccountManager>() {@Overridepublic AccountManager createService(ContextImpl ctx) throws ServiceNotFoundException {IBinder b = ServiceManager.getServiceOrThrow(Context.ACCOUNT_SERVICE);IAccountManager service = IAccountManager.Stub.asInterface(b);return new AccountManager(ctx, service);}});
...
}

而调用呢,则看我们之前说的应用层ContextImpl的getSystemService方法

    // The system service cache for the system services that are cached per-ContextImpl.final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();
    @Overridepublic Object getSystemService(String name) {return SystemServiceRegistry.getSystemService(this, name);}

SystemServiceRegistry

    // Service registry information.// This information is never changed once static initialization has completed.private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =new HashMap<Class<?>, String>();private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =new HashMap<String, ServiceFetcher<?>>();    /*** Gets a system service from a given context.*/public static Object getSystemService(ContextImpl ctx, String name) {ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);return fetcher != null ? fetcher.getService(ctx) : null;}/*** Statically registers a system service with the context.* This method must be called during static initialization only.*/private static <T> void registerService(String serviceName, Class<T> serviceClass,ServiceFetcher<T> serviceFetcher) {SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);}

这里主要就弄清了一件事,WifiManager是aidl的客户端,具体逻辑还是要去看服务端的。即看下Service对应代码:

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

而之前在(四十一) SystemServer初探有说到WifiService

                // Wifi Service must be started first for wifi-related services.traceBeginAndSlog("StartWifi");mSystemServiceManager.startService(WIFI_SERVICE_CLASS);traceEnd();
    private static final String WIFI_SERVICE_CLASS ="com.android.server.wifi.WifiService";

这里感觉是有关的。

ServiceManager是这样的:

public final class ServiceManager {private static final String TAG = "ServiceManager";/*** Returns a reference to a service with the given name.* * @param name the name of the service to get* @return a reference to the service, or <code>null</code> if the service doesn't exist*/public static IBinder getService(String name) {try {IBinder service = sCache.get(name);if (service != null) {return service;} else {return Binder.allowBlocking(getIServiceManager().getService(name));}} catch (RemoteException e) {Log.e(TAG, "error in getService", e);}return null;}/*** Returns a reference to a service with the given name, or throws* {@link NullPointerException} if none is found.** @hide*/public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {final IBinder binder = getService(name);if (binder != null) {return binder;} else {throw new ServiceNotFoundException(name);}}
.../*** This is only intended to be called when the process is first being brought* up and bound by the activity manager. There is only one thread in the process* at that time, so no locking is done.* * @param cache the cache of service references* @hide*/public static void initServiceCache(Map<String, IBinder> cache) {if (sCache.size() != 0) {throw new IllegalStateException("setServiceCache may only be called once");}sCache.putAll(cache);}

可以看到Service的IBinder要么从cache里取出来的,要么getIServiceManager().getService(name)取到的,那就先看下initServiceCache是在哪里调用的?

./base/core/java/android/app/ActivityThread.java

        public final void bindApplication(String processName, ApplicationInfo appInfo,List<ProviderInfo> providers, ComponentName instrumentationName,ProfilerInfo profilerInfo, Bundle instrumentationArgs,IInstrumentationWatcher instrumentationWatcher,IUiAutomationConnection instrumentationUiConnection, int debugMode,boolean enableBinderTracking, boolean trackAllocation,boolean isRestrictedBackupMode, boolean persistent, Configuration config,CompatibilityInfo compatInfo, Map services, Bundle coreSettings,String buildSerial) {if (services != null) {// Setup the service cache in the ServiceManagerServiceManager.initServiceCache(services);}

那bindApplication是在 哪里调用的呢?

AMS:

           if (app.instr != null) {thread.bindApplication(processName, appInfo, providers,app.instr.mClass,profilerInfo, app.instr.mArguments,app.instr.mWatcher,app.instr.mUiAutomationConnection, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.persistent,new Configuration(getGlobalConfiguration()), app.compat,getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial);} else {thread.bindApplication(processName, appInfo, providers, null, profilerInfo,null, null, null, testMode,mBinderTransactionTrackingEnabled, enableTrackAllocation,isRestrictedBackupMode || !normalMode, app.persistent,new Configuration(getGlobalConfiguration()), app.compat,getCommonServicesLocked(app.isolated),mCoreSettingsObserver.getCoreSettingsLocked(),buildSerial);}
    /*** Initialize the application bind args. These are passed to each* process when the bindApplication() IPC is sent to the process. They're* lazily setup to make sure the services are running when they're asked for.*/private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {// Isolated processes won't get this optimization, so that we don't// violate the rules about which services they have access to.if (isolated) {if (mIsolatedAppBindArgs == null) {mIsolatedAppBindArgs = new HashMap<>();mIsolatedAppBindArgs.put("package", ServiceManager.getService("package"));}return mIsolatedAppBindArgs;}if (mAppBindArgs == null) {mAppBindArgs = new HashMap<>();// Setup the application init argsmAppBindArgs.put("package", ServiceManager.getService("package"));mAppBindArgs.put("window", ServiceManager.getService("window"));mAppBindArgs.put(Context.ALARM_SERVICE,ServiceManager.getService(Context.ALARM_SERVICE));}return mAppBindArgs;}

这里少了wifi相关的Service,所以还是走的

getIServiceManager().getService(name)
    private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}// Find the service managersServiceManager = ServiceManagerNative.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));return sServiceManager;}

这里梳理不下去了=-=尴尬,待续。。。有兴趣的可以看下https://www.jianshu.com/p/93644d6f9e02

“从最表层的API过度到JNI层,然后与Lib层通讯”什么鬼,我只是个java工程师=-=

先给个结论,wifiManager调用接口是调用到WifiServiceImpl那边去了。

-------------------------------2018/6/19日更新,native层的正推没办法了,从倒推开始吧----------------------------------------

之前讲过WifiService是在SystemServer启动起来的,流程如下:

SystemServer.java:

                // Wifi Service must be started first for wifi-related services.traceBeginAndSlog("StartWifi");mSystemServiceManager.startService(WIFI_SERVICE_CLASS);traceEnd();

SystemServiceManager:

简单来说就是调用下WIFI_SERVICE_CLASS("com.android.server.wifi.WifiService")的构造器和onStart方法

/*** Starts a service by class name.** @return The service instance.*/@SuppressWarnings("unchecked")public SystemService startService(String className) {final Class<SystemService> serviceClass;try {serviceClass = (Class<SystemService>)Class.forName(className);} catch (ClassNotFoundException ex) {Slog.i(TAG, "Starting " + className);throw new RuntimeException("Failed to create service " + className+ ": service class not found, usually indicates that the caller should "+ "have called PackageManager.hasSystemFeature() to check whether the "+ "feature is available on this device before trying to start the "+ "services that implement it", ex);}return startService(serviceClass);}/*** Creates and starts a system service. The class must be a subclass of* {@link com.android.server.SystemService}.** @param serviceClass A Java class that implements the SystemService interface.* @return The service instance, never null.* @throws RuntimeException if the service fails to start.*/@SuppressWarnings("unchecked")public <T extends SystemService> T startService(Class<T> serviceClass) {try {final String name = serviceClass.getName();Slog.i(TAG, "Starting " + name);Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);// Create the service.if (!SystemService.class.isAssignableFrom(serviceClass)) {throw new RuntimeException("Failed to create " + name+ ": service must extend " + SystemService.class.getName());}final T service;try {Constructor<T> constructor = serviceClass.getConstructor(Context.class);service = constructor.newInstance(mContext);} catch (InstantiationException ex) {throw new RuntimeException("Failed to create service " + name+ ": service could not be instantiated", ex);} catch (IllegalAccessException ex) {throw new RuntimeException("Failed to create service " + name+ ": service must have a public constructor with a Context argument", ex);} catch (NoSuchMethodException ex) {throw new RuntimeException("Failed to create service " + name+ ": service must have a public constructor with a Context argument", ex);} catch (InvocationTargetException ex) {throw new RuntimeException("Failed to create service " + name+ ": service constructor threw an exception", ex);}startService(service);return service;} finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}}public void startService(@NonNull final SystemService service) {// Register it.mServices.add(service);// Start it.long time = SystemClock.elapsedRealtime();try {service.onStart();} catch (RuntimeException ex) {throw new RuntimeException("Failed to start service " + service.getClass().getName()+ ": onStart threw an exception", ex);}warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");}

WifiService:

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));}@Overridepublic void onStart() {Log.i(TAG, "Registering " + Context.WIFI_SERVICE);publishBinderService(Context.WIFI_SERVICE, mImpl);}

SystemService:

    protected final void publishBinderService(String name, IBinder service) {publishBinderService(name, service, false);}/*** Publish the service so it is accessible to other services and apps.*/protected final void publishBinderService(String name, IBinder service,boolean allowIsolated) {ServiceManager.addService(name, service, allowIsolated);}

这边的addService方法和getService方法是对应起来的,一个get,一个add。

所以之前的getService方法就是WifiServiceImpl。

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

2.2.2 Service的WiFi启动流程

先看下WifiServiceImpl流程:

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.*/@Overridepublic 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 Wifiif (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 wifiboolean 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 toggledreturn 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;}mWifiController.sendMessage(CMD_WIFI_TOGGLED);return true;}

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

    private void persistWifiState(int state) {final ContentResolver cr = mContext.getContentResolver();mPersistWifiState = state;Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);}
    /* Values tracked in Settings.Global.WIFI_ON */static final int WIFI_DISABLED                      = 0;static final int WIFI_ENABLED                       = 1;/* Wifi enabled while in airplane mode */private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE     = 2;/* Wifi disabled due to airplane mode on */private static final int WIFI_DISABLED_AIRPLANE_ON          = 3;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;}

这里接着会调用到WifiController,WifiController是个状态机设计模式,也就是说会根据WiFi的不同状态决定处理WiFi消息的不同逻辑。

初始化逻辑如下:

        addState(mDefaultState);addState(mApStaDisabledState, mDefaultState);addState(mStaEnabledState, mDefaultState);addState(mDeviceActiveState, mStaEnabledState);addState(mDeviceInactiveState, mStaEnabledState);addState(mScanOnlyLockHeldState, mDeviceInactiveState);addState(mFullLockHeldState, mDeviceInactiveState);addState(mFullHighPerfLockHeldState, mDeviceInactiveState);addState(mNoLockHeldState, mDeviceInactiveState);addState(mStaDisabledWithScanState, mDefaultState);addState(mApEnabledState, mDefaultState);addState(mEcmState, mDefaultState);

2.2.3 WifiController

WifiController的状态比较多,而我比较关注从关闭到打开的状态变化,即:

   class ApStaDisabledState extends State {private int mDeferredEnableSerialNumber = 0;private boolean mHaveDeferredEnable = false;private long mDisabledTimestamp;@Overridepublic void enter() {mWifiStateMachine.setSupplicantRunning(false);// Supplicant can't restart right away, so not the time we switched offmDisabledTimestamp = SystemClock.elapsedRealtime();mDeferredEnableSerialNumber++;mHaveDeferredEnable = false;mWifiStateMachine.clearANQPCache();}@Overridepublic boolean processMessage(Message msg) {switch (msg.what) {case CMD_WIFI_TOGGLED:case CMD_AIRPLANE_TOGGLED:if (mSettingsStore.isWifiToggleEnabled()) {if (doDeferEnable(msg)) {if (mHaveDeferredEnable) {//  have 2 toggles now, inc serial number an ignore bothmDeferredEnableSerialNumber++;}mHaveDeferredEnable = !mHaveDeferredEnable;break;}if (mDeviceIdle == false) {// wifi is toggled, we need to explicitly tell WifiStateMachine that we// are headed to connect mode before going to the DeviceActiveState// since that will start supplicant and WifiStateMachine may not know// what state to head to (it might go to scan mode).mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);transitionTo(mDeviceActiveState);} else {checkLocksAndTransitionWhenDeviceIdle();}} else if (mSettingsStore.isScanAlwaysAvailable()) {transitionTo(mStaDisabledWithScanState);}break;mSettingsStore.isWifiToggleEnabled()) {if (doDeferEnable(msg)) {if (mHaveDeferredEnable) {//  have 2 toggles now, inc serial number an ignore bothmDeferredEnableSerialNumber++;}mHaveDeferredEnable = !mHaveDeferredEnable;break;}if (mDeviceIdle == false) {// wifi is toggled, we need to explicitly tell WifiStateMachine that we// are headed to connect mode before going to the DeviceActiveState// since that will start supplicant and WifiStateMachine may not know// what state to head to (it might go to scan mode).mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);transitionTo(mDeviceActiveState);} else {checkLocksAndTransitionWhenDeviceIdle();}} else if (mSettingsStore.isScanAlwaysAvailable()) {transitionTo(mStaDisabledWithScanState);}break;

现在就上面一串代码挨个解析。

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);/*** See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}.  This is the default value if a* Settings.Global value is not present.  This is the minimum time after wifi is disabled* we'll act on an enable.  Enable requests received before this delay will be deferred.*/private static final long DEFAULT_REENABLE_DELAY_MS = 500;

wifi关闭后立刻打开有可能流程还没走完导致问题(压力测试会频繁开关WiFi),所以这边Google应该考虑到这点加了个最短时限500ms,如果短于这时间,就强迫补个差来个500+5ms的延时。

以小于500ms的间隔发送消息会由于mDeferredEnableSerialNumber值自增导致前一个消息失效。

                case CMD_DEFERRED_TOGGLE:if (msg.arg1 != mDeferredEnableSerialNumber) {log("DEFERRED_TOGGLE ignored due to serial mismatch");break;}log("DEFERRED_TOGGLE handled");sendMessage((Message)(msg.obj));break;

接着状态机会走到如下逻辑中去,除了WifiStateMachine外,还会将状态改为mDeviceActiveState。

                            // wifi is toggled, we need to explicitly tell WifiStateMachine that we// are headed to connect mode before going to the DeviceActiveState// since that will start supplicant and WifiStateMachine may not know// what state to head to (it might go to scan mode).mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);transitionTo(mDeviceActiveState);

由于是一个类,看下StaEnabledState(DeviceActiveState的父状态)和DeviceActiveState,状态机设计模式状态改变会先走进父状态的enter中。

    class StaEnabledState extends State {@Overridepublic void enter() {mWifiStateMachine.setSupplicantRunning(true);}
    /* Parent: StaEnabledState */class DeviceActiveState extends State {@Overridepublic void enter() {mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);mWifiStateMachine.setHighPerfModeEnabled(false);}

可以看到其实是调用顺序

 
  1. mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
  2. mWifiStateMachine.setSupplicantRunning(true);
  3. mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
  4. mWifiStateMachine.setHighPerfModeEnabled(false);

2.2.4 WifiStateMachine

wifiStateMachine也是一个状态机:

        // CHECKSTYLE:OFF IndentationCheckaddState(mDefaultState);addState(mInitialState, mDefaultState);addState(mSupplicantStartingState, mDefaultState);addState(mSupplicantStartedState, mDefaultState);addState(mScanModeState, mSupplicantStartedState);addState(mConnectModeState, mSupplicantStartedState);addState(mL2ConnectedState, mConnectModeState);addState(mObtainingIpState, mL2ConnectedState);addState(mConnectedState, mL2ConnectedState);addState(mRoamingState, mL2ConnectedState);addState(mDisconnectingState, mConnectModeState);addState(mDisconnectedState, mConnectModeState);addState(mWpsRunningState, mConnectModeState);addState(mWaitForP2pDisableState, mSupplicantStartedState);addState(mSupplicantStoppingState, mDefaultState);addState(mSoftApState, mDefaultState);// CHECKSTYLE:ON IndentationCheck

这里看下WifiController下发的4个操作

1、3)setOperationalMode:

/*** Track the state of Wifi connectivity. All event handling is done here,* and all changes in connectivity state are initiated here.** Wi-Fi now supports three modes of operation: Client, SoftAp and p2p* In the current implementation, we support concurrent wifi p2p and wifi operation.* The WifiStateMachine handles SoftAp and Client operations while WifiP2pService* handles p2p operation.** @hide*/
public class WifiStateMachine extends StateMachine implements WifiNative.WifiRssiEventHandler,WifiMulticastLockManager.FilterController {    
    /*** TODO: doc*/public void setOperationalMode(int mode) {if (mVerboseLoggingEnabled) log("setting operational mode to " + String.valueOf(mode));sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);})

2)setSupplicantRunning

    /**
     * TODO: doc*/public void setSupplicantRunning(boolean enable) {if (enable) {sendMessage(CMD_START_SUPPLICANT);} else {sendMessage(CMD_STOP_SUPPLICANT);}}

4)  setHighPerfModeEnabled

   /*** Set high performance mode of operation.* Enabling would set active power mode and disable suspend optimizations;* disabling would set auto power mode and enable suspend optimizations** @param enable true if enable, false otherwise*/public void setHighPerfModeEnabled(boolean enable) {sendMessage(CMD_SET_HIGH_PERF_MODE, enable ? 1 : 0, 0);}

来看下初始状态对消息的处理

    class InitialState extends State {private void cleanup() {// Tearing down the client interfaces below is going to stop our supplicant.mWifiMonitor.stopAllMonitoring();mDeathRecipient.unlinkToDeath();mWifiNative.tearDown();}@Overridepublic void enter() {mWifiStateTracker.updateState(WifiStateTracker.INVALID);cleanup();}@Overridepublic boolean processMessage(Message message) {logStateAndMessage(message, this);switch (message.what) {case CMD_START_SUPPLICANT:Pair<Integer, IClientInterface> statusAndInterface =mWifiNative.setupForClientMode();if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) {mClientInterface = statusAndInterface.second;} else {incrementMetricsForSetupFailure(statusAndInterface.first);}if (mClientInterface == null|| !mDeathRecipient.linkToDeath(mClientInterface.asBinder())) {setWifiState(WifiManager.WIFI_STATE_UNKNOWN);cleanup();break;}try {// A runtime crash or shutting down AP mode can leave// IP addresses configured, and this affects// connectivity when supplicant starts up.// Ensure we have no IP addresses before a supplicant start.mNwService.clearInterfaceAddresses(mInterfaceName);// Set privacy extensionsmNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);// IPv6 is enabled only as long as access point is connected since:// - IPv6 addresses and routes stick around after disconnection// - kernel is unaware when connected and fails to start IPv6 negotiation// - kernel can start autoconfiguration when 802.1x is not completemNwService.disableIpv6(mInterfaceName);} catch (RemoteException re) {loge("Unable to change interface settings: " + re);} catch (IllegalStateException ie) {loge("Unable to change interface settings: " + ie);}if (!mWifiNative.enableSupplicant()) {loge("Failed to start supplicant!");setWifiState(WifiManager.WIFI_STATE_UNKNOWN);cleanup();break;}if (mVerboseLoggingEnabled) log("Supplicant start successful");mWifiMonitor.startMonitoring(mInterfaceName, true);mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts();setSupplicantLogLevel();transitionTo(mSupplicantStartingState);break;case CMD_START_AP:transitionTo(mSoftApState);break;case CMD_SET_OPERATIONAL_MODE:mOperationalMode = message.arg1;if (mOperationalMode != DISABLED_MODE) {sendMessage(CMD_START_SUPPLICANT);}break;default:return NOT_HANDLED;}return HANDLED;}}

在InitialState 中 1、 3 步最后走的逻辑和第2步是一样的,都是发出了一个CMD_START_SUPPLICANT消息,不是很懂这块处理逻辑=-=搜了下真正对CONNECT_MODE有处理的是以下状态,应该是第3步发出的消息会得到ScanModeState的处理:

   class ScanModeState extends State {private int mLastOperationMode;@Overridepublic void enter() {mLastOperationMode = mOperationalMode;mWifiStateTracker.updateState(WifiStateTracker.SCAN_MODE);}@Overridepublic boolean processMessage(Message message) {logStateAndMessage(message, this);switch(message.what) {case CMD_SET_OPERATIONAL_MODE:if (message.arg1 == CONNECT_MODE) {mOperationalMode = CONNECT_MODE;setWifiState(WIFI_STATE_ENABLING);transitionTo(mDisconnectedState);} else if (message.arg1 == DISABLED_MODE) {transitionTo(mSupplicantStoppingState);}// Nothing to dobreak;// Handle scan. All the connection related commands are// handled only in ConnectModeStatecase CMD_START_SCAN:handleScanRequest(message);break;default:return NOT_HANDLED;}return HANDLED;}}

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

  1. mWifiNative.enableSupplicant()
  2. mWifiMonitor.startMonitoring(mInterfaceName, true);
  3. 切换到SupplicantStartingState状态

PS:

    /*** Enable wpa_supplicant via wificond.* @return Returns true on success.*/public boolean enableSupplicant() {return mWificondControl.enableSupplicant();}
    /*** Start Monitoring for wpa_supplicant events.** @param iface Name of iface.* TODO: Add unit tests for these once we remove the legacy code.*/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!");}}

看切换完了再收到这个消息后就是延迟发送了,后面估计是轮到哪个状态就是不同的处理逻辑的,但就我看来这个消息主要就是start supplicant的,start完了应该完成任务了。

                case CMD_SET_OPERATIONAL_MODE:messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;deferMessage(message);break;

至于第4步

SupplicantStartedState状态会处理:

                case CMD_SET_HIGH_PERF_MODE:if (message.arg1 == 1) {setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);} else {setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);}break;

都是WifiNative的代码,溜了溜了。

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

感觉分析的有点糙,再看看,后期不定时完善。。。

继续梳理见

1.(五十八)Android O WiFi启动流程梳理续——setupForClientMode

2.(五十九)Android O WiFi启动流程梳理续——enableSupplicant

3. 总结

(四十四)Android O WiFi启动流程梳理相关推荐

  1. (七十)Android O Service启动流程梳理——bindService

    前言:最近在处理anr问题的时候迫切需要搞清楚service的启动流程,抽时间梳理一下. 1.service启动简述 service启动分三种,比较简单的就是startService,Android ...

  2. Android 11 WiFi启动流程

    欢迎大家一起学习探讨通信之WLAN.本节重点基于Android11分析讨论WiFi开启流程.用户点击一下"WiFi"开关,WiFi开启了.看似如此简单操作,但系统流程调用还是相当复 ...

  3. Android 11 WiFi扫描流程梳理

    上一篇我们梳理了WiFi的开启流程,Android11 WiFi开启流程,在最后我们说到ActiveModeWarden中注册了ClientListener监听器.我们接着这个逻辑继续梳理一下打开Wi ...

  4. 【Android 12.0】Android S WiFi启动业务流程分析(UML图)

    以下两张为Android S的WiFi启动(start)业务流程UML图,业务流程的过程详情因公司规定不可复制源码出来,所以想看业务流程详情的同学可以参考其他博主所发的博客.业务流程参考内容链接我会放 ...

  5. Android -- Wifi启动流程分析

    Android -- Wifi启动流程分析 Android网络各个模式中,Wifi应该是目前最常用的一种网络方式了:下面就简单介绍下Android中Wifi的启动流程. 当我在Setting菜单里点击 ...

  6. [系统安全] 四十四.APT系列(9)Metasploit技术之基础用法万字详解及防御机理

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  7. 结合源码探讨Android系统的启动流程

    结合源码探讨Android系统的启动流程 由于本人能力有限,所考虑或者疏忽错漏的地方或多或少应该存在.同时,Android从启动过程开始,实际上就涉及多个技术难点和多种通信机制的知识点. 基于上面两个 ...

  8. Android平台WIFI启动流程之二

    http://blog.sina.com.cn/s/blog_13146f9590101wji1.html [摘要] 本文从用户界面出发,从应用层到硬件适配层,对Android平台wifi启动和关闭的 ...

  9. 【正点原子Linux连载】第四十四章 设备树下的LED驱动实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

最新文章

  1. 清华大学王玉计算机,王玉珏(清华大学环境学院教授)_百度百科
  2. “时隔 10 年,重新开始写代码的我要崩溃了!”
  3. android 建数据库 SQLite 存储sd 卡或者内存
  4. Site Definition和Web Template的区别
  5. 【蓝桥杯Java_C组·从零开始卷】第六节(一)、Java常用数学函数
  6. 洛谷3320 SDOI2015寻宝游戏(set+dfs序)(反向迭代器的注意事项!)
  7. FreeEIM 来点新知识iOS UIScrollView详解
  8. 关于C++的建议,仅仅为了规范代码(一)
  9. UIApplication委托信息(多任务)
  10. 【spring】注解开发和spring整合junit
  11. Java学习笔记9(面象对象9:多态)
  12. C++ API 设计 15 第十章 测试
  13. 戴姆勒集团将拆分卡车业务;洲际酒店集团发布全新品牌标识;先正达集团中国创新研发中心落户南京 | 美通企业周刊...
  14. gltf模型浏览器_腾讯硬核干货!如何在页面极速渲染3D模型
  15. 1138 Postorder Traversal
  16. jbpm 历史查询笔记
  17. 单向链表中查找倒数第K个数
  18. 【转】关于测试工程师的几个笑话
  19. 如何下载网页中的图片
  20. 【C++入门篇】深入理解函数重载

热门文章

  1. plc模拟量与通信控制应用实践_PLC 应用技术——编程、通信、装调、案例
  2. geostudio2007破解版使用碰到的问题
  3. 好玩又有趣的APP分享
  4. shader卡通渲染
  5. 前端 iOS 和 Android 的兼容问题
  6. 营改增后不能抵扣的15种专用发票情形
  7. Android平台上实现身份证识别(通过阿里云Api-印刷文字识别_身份证识别)
  8. shell那点事儿——运维工程师必会shell知识
  9. 艾永亮:超级产品与营销的本质区别
  10. 新的一年里技术管理者(工作者)们如何做好技术规划?