Android O WiFi启动流程

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/sinat_20059415/article/details/80716763

前言:最近又重新拿起来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


 
 
  1. /**
  2. * @return new WifiEnabler or null (as overridden by WifiSettingsForSetupWizard)
  3. */
  4. private WifiEnabler createWifiEnabler() {
  5. final SettingsActivity activity = (SettingsActivity) getActivity();
  6. return new WifiEnabler(activity, new SwitchBarController(activity.getSwitchBar()),
  7. mMetricsFeatureProvider);
  8. }

 

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


 
 
  1. public class SwitchBarController extends SwitchWidgetController implements
  2. SwitchBar. OnSwitchChangeListener {
  3. private final SwitchBar mSwitchBar;
  4. public SwitchBarController(SwitchBar switchBar) {
  5. mSwitchBar = switchBar;
  6. }
  7. ...

 
 
  1.     @Override
  2.     public void startListening() {
  3.         mSwitchBar.addOnSwitchChangeListener( this);
  4.     }

 
 
  1. ...
  2. @Override
  3. public void onSwitchChanged(Switch switchView, boolean isChecked) {
  4. if (mListener != null) {
  5. mListener.onSwitchToggled(isChecked);
  6. }
  7. }

 

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


 
 
  1. @VisibleForTesting
  2. WifiEnabler(Context context, SwitchWidgetController switchWidget,
  3. MetricsFeatureProvider metricsFeatureProvider,
  4. ConnectivityManagerWrapper connectivityManagerWrapper) {
  5. mContext = context;
  6. mSwitchWidget = switchWidget;
  7. mSwitchWidget.setListener( this);
  8. mMetricsFeatureProvider = metricsFeatureProvider;
  9. mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
  10. mConnectivityManager = connectivityManagerWrapper;
  11. mIntentFilter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION);
  12. // The order matters! We really should not depend on this. :(
  13. mIntentFilter.addAction(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION);
  14. mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
  15. setupSwitchController();
  16. }
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(); }

 
 
  1. public void setupSwitchController() {
  2. final int state = mWifiManager.getWifiState();
  3. handleWifiStateChanged(state);
  4. if (!mListeningToOnSwitchChange) {
  5. mSwitchWidget.startListening();
  6. mListeningToOnSwitchChange = true;
  7. }
  8. mSwitchWidget.setupView();
  9. }

 
 
  1. @Override
  2. public boolean onSwitchToggled(boolean isChecked) {
  3. //Do nothing if called as a result of a state machine event
  4. if (mStateMachineEvent) {
  5. return true;
  6. }
  7. // Show toast message if Wi-Fi is not allowed in airplane mode
  8. if (isChecked && !WirelessUtils.isRadioAllowed(mContext, Settings.Global.RADIO_WIFI)) {
  9. Toast.makeText(mContext, R.string.wifi_in_airplane_mode, Toast.LENGTH_SHORT).show();
  10. // Reset switch to off. No infinite check/listenenr loop.
  11. mSwitchWidget.setChecked( false);
  12. return false;
  13. }
  14. // Disable tethering if enabling Wifi
  15. if (mayDisableTethering(isChecked)) {
  16. mConnectivityManager.stopTethering(ConnectivityManager.TETHERING_WIFI);
  17. }
  18. if (isChecked) {
  19. mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_ON);
  20. } else {
  21. // Log if user was connected at the time of switching off.
  22. mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_WIFI_OFF,
  23. mConnected. get());
  24. }
  25. if (!mWifiManager.setWifiEnabled(isChecked)) {
  26. // Error
  27. mSwitchWidget.setEnabled( true);
  28. Toast.makeText(mContext, R.string.wifi_error, Toast.LENGTH_SHORT).show();
  29. }
  30. return true;
  31. }
mWifiManager.setWifiEnabled(isChecked)) { // Error mSwitchWidget.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


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

2.2.1 WifiService是什么

而mService是啥呢


 
 
  1. IWifiManager mService;
  2. /**
  3. * Create a new WifiManager instance.
  4. * Applications will almost always want to use
  5. * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
  6. * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
  7. * @param context the application context
  8. * @param service the Binder interface
  9. * @hide - hide this because it takes in a parameter of type IWifiManager, which
  10. * is a system private class.
  11. */
  12. public WifiManager(Context context, IWifiManager service, Looper looper) {
  13. mContext = context;
  14. mService = service;
  15. mLooper = looper;
  16. mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
  17. }

应用层的WifiManager都是这么来的

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

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

有这么一个类:

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


 
 
  1. registerService(Context.WIFI_SERVICE, WifiManager.class,
  2. new CachedServiceFetcher<WifiManager>() {
  3. @Override
  4. public WifiManager createService(ContextImpl ctx) throws ServiceNotFoundException {
  5. IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SERVICE);
  6. IWifiManager service = IWifiManager.Stub.asInterface(b);
  7. return new WifiManager(ctx.getOuterContext(), service,
  8. ConnectivityThread.getInstanceLooper());
  9. }});

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


 
 
  1. final class SystemServiceRegistry {
  2. ...
  3. // Not instantiable.
  4. private SystemServiceRegistry() { }
  5. static {
  6. registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
  7. new CachedServiceFetcher<AccessibilityManager>() {
  8. @Override
  9. public AccessibilityManager createService(ContextImpl ctx) {
  10. return AccessibilityManager.getInstance(ctx);
  11. }});
  12. registerService(Context.CAPTIONING_SERVICE, CaptioningManager.class,
  13. new CachedServiceFetcher<CaptioningManager>() {
  14. @Override
  15. public CaptioningManager createService(ContextImpl ctx) {
  16. return new CaptioningManager(ctx);
  17. }});
  18. registerService(Context.ACCOUNT_SERVICE, AccountManager.class,
  19. new CachedServiceFetcher<AccountManager>() {
  20. @Override
  21. public AccountManager createService(ContextImpl ctx) throws ServiceNotFoundException {
  22. IBinder b = ServiceManager.getServiceOrThrow(Context.ACCOUNT_SERVICE);
  23. IAccountManager service = IAccountManager.Stub.asInterface(b);
  24. return new AccountManager(ctx, service);
  25. }});
  26. ...
  27. }

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


 
 
  1. // The system service cache for the system services that are cached per-ContextImpl.
  2. final Object[] mServiceCache = SystemServiceRegistry.createServiceCache();

 
 
  1. @Override
  2. public Object getSystemService(String name) {
  3. return SystemServiceRegistry.getSystemService( this, name);
  4. }

SystemServiceRegistry


 
 
  1. // Service registry information.
  2. // This information is never changed once static initialization has completed.
  3. private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
  4. new HashMap<Class<?>, String>();
  5. private static final HashMap< String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
  6. new HashMap< String, ServiceFetcher<?>>();
  7. /**
  8. * Gets a system service from a given context.
  9. */
  10. public static Object getSystemService(ContextImpl ctx, String name) {
  11. ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
  12. return fetcher != null ? fetcher.getService(ctx) : null;
  13. }
  14. /**
  15. * Statically registers a system service with the context.
  16. * This method must be called during static initialization only.
  17. */
  18. private static <T> void registerService( String serviceName, Class<T> serviceClass,
  19. ServiceFetcher<T> serviceFetcher) {
  20. SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
  21. SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
  22. }

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

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

 

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

 


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

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

这里感觉是有关的。

ServiceManager是这样的:


 
 
  1. public final class ServiceManager {
  2. private static final String TAG = "ServiceManager";
  3. /**
  4. * Returns a reference to a service with the given name.
  5. *
  6. * @param name the name of the service to get
  7. * @return a reference to the service, or <code>null</code> if the service doesn't exist
  8. */
  9. public static IBinder getService(String name) {
  10. try {
  11. IBinder service = sCache.get(name);
  12. if (service != null) {
  13. return service;
  14. } else {
  15. return Binder.allowBlocking(getIServiceManager().getService(name));
  16. }
  17. } catch (RemoteException e) {
  18. Log.e(TAG, "error in getService", e);
  19. }
  20. return null;
  21. }
  22. /**
  23. * Returns a reference to a service with the given name, or throws
  24. * {@link NullPointerException} if none is found.
  25. *
  26. * @hide
  27. */
  28. public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {
  29. final IBinder binder = getService(name);
  30. if (binder != null) {
  31. return binder;
  32. } else {
  33. throw new ServiceNotFoundException(name);
  34. }
  35. }
  36. ...
  37. /**
  38. * This is only intended to be called when the process is first being brought
  39. * up and bound by the activity manager. There is only one thread in the process
  40. * at that time, so no locking is done.
  41. *
  42. * @param cache the cache of service references
  43. * @hide
  44. */
  45. public static void initServiceCache(Map<String, IBinder> cache) {
  46. if (sCache.size() != 0) {
  47. throw new IllegalStateException( "setServiceCache may only be called once");
  48. }
  49. sCache.putAll(cache);
  50. }

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

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


 
 
  1. public final void bindApplication(String processName, ApplicationInfo appInfo,
  2. List<ProviderInfo> providers, ComponentName instrumentationName,
  3. ProfilerInfo profilerInfo, Bundle instrumentationArgs,
  4. IInstrumentationWatcher instrumentationWatcher,
  5. IUiAutomationConnection instrumentationUiConnection, int debugMode,
  6. boolean enableBinderTracking, boolean trackAllocation,
  7. boolean isRestrictedBackupMode, boolean persistent, Configuration config,
  8. CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
  9. String buildSerial) {
  10. if (services != null) {
  11. // Setup the service cache in the ServiceManager
  12. ServiceManager.initServiceCache(services);
  13. }

那bindApplication是在 哪里调用的呢?

AMS:


 
 
  1. if (app. instr != null) {
  2. thread.bindApplication(processName, appInfo, providers,
  3. app. instr.mClass,
  4. profilerInfo, app. instr.mArguments,
  5. app. instr.mWatcher,
  6. app. instr.mUiAutomationConnection, testMode,
  7. mBinderTransactionTrackingEnabled, enableTrackAllocation,
  8. isRestrictedBackupMode || !normalMode, app.persistent,
  9. new Configuration(getGlobalConfiguration()), app.compat,
  10. getCommonServicesLocked(app.isolated),
  11. mCoreSettingsObserver.getCoreSettingsLocked(),
  12. buildSerial);
  13. } else {
  14. thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
  15. null, null, null, testMode,
  16. mBinderTransactionTrackingEnabled, enableTrackAllocation,
  17. isRestrictedBackupMode || !normalMode, app.persistent,
  18. new Configuration(getGlobalConfiguration()), app.compat,
  19. getCommonServicesLocked(app.isolated),
  20. mCoreSettingsObserver.getCoreSettingsLocked(),
  21. buildSerial);
  22. }

 
 
  1. /**
  2. * Initialize the application bind args. These are passed to each
  3. * process when the bindApplication() IPC is sent to the process. They're
  4. * lazily setup to make sure the services are running when they're asked for.
  5. */
  6. private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
  7. // Isolated processes won't get this optimization, so that we don't
  8. // violate the rules about which services they have access to.
  9. if (isolated) {
  10. if (mIsolatedAppBindArgs == null) {
  11. mIsolatedAppBindArgs = new HashMap<>();
  12. mIsolatedAppBindArgs.put( "package", ServiceManager.getService( "package"));
  13. }
  14. return mIsolatedAppBindArgs;
  15. }
  16. if (mAppBindArgs == null) {
  17. mAppBindArgs = new HashMap<>();
  18. // Setup the application init args
  19. mAppBindArgs.put( "package", ServiceManager.getService( "package"));
  20. mAppBindArgs.put( "window", ServiceManager.getService( "window"));
  21. mAppBindArgs.put(Context.ALARM_SERVICE,
  22. ServiceManager.getService(Context.ALARM_SERVICE));
  23. }
  24. return mAppBindArgs;
  25. }

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

getIServiceManager().getService(name)
 
 

 
 
  1. private static IServiceManager getIServiceManager() {
  2. if (sServiceManager != null) {
  3. return sServiceManager;
  4. }
  5. // Find the service manager
  6. sServiceManager = ServiceManagerNative
  7. .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
  8. return sServiceManager;
  9. }

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

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

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

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

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

SystemServer.java:


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

SystemServiceManager:

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


 
 
  1. /**
  2. * Starts a service by class name.
  3. *
  4. * @return The service instance.
  5. */
  6. @SuppressWarnings( "unchecked")
  7. public SystemService startService(String className) {
  8. final Class<SystemService> serviceClass;
  9. try {
  10. serviceClass = (Class<SystemService>)Class.forName(className);
  11. } catch (ClassNotFoundException ex) {
  12. Slog.i(TAG, "Starting " + className);
  13. throw new RuntimeException( "Failed to create service " + className
  14. + ": service class not found, usually indicates that the caller should "
  15. + "have called PackageManager.hasSystemFeature() to check whether the "
  16. + "feature is available on this device before trying to start the "
  17. + "services that implement it", ex);
  18. }
  19. return startService(serviceClass);
  20. }
  21. /**
  22. * Creates and starts a system service. The class must be a subclass of
  23. * {@link com.android.server.SystemService}.
  24. *
  25. * @param serviceClass A Java class that implements the SystemService interface.
  26. * @return The service instance, never null.
  27. * @throws RuntimeException if the service fails to start.
  28. */
  29. @SuppressWarnings( "unchecked")
  30. public <T extends SystemService> T startService(Class<T> serviceClass) {
  31. try {
  32. final String name = serviceClass.getName();
  33. Slog.i(TAG, "Starting " + name);
  34. Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
  35. // Create the service.
  36. if (!SystemService.class.isAssignableFrom(serviceClass)) {
  37. throw new RuntimeException( "Failed to create " + name
  38. + ": service must extend " + SystemService.class.getName());
  39. }
  40. final T service;
  41. try {
  42. Constructor<T> constructor = serviceClass.getConstructor(Context.class);
  43. service = constructor.newInstance(mContext);
  44. } catch (InstantiationException ex) {
  45. throw new RuntimeException( "Failed to create service " + name
  46. + ": service could not be instantiated", ex);
  47. } catch (IllegalAccessException ex) {
  48. throw new RuntimeException( "Failed to create service " + name
  49. + ": service must have a public constructor with a Context argument", ex);
  50. } catch (NoSuchMethodException ex) {
  51. throw new RuntimeException( "Failed to create service " + name
  52. + ": service must have a public constructor with a Context argument", ex);
  53. } catch (InvocationTargetException ex) {
  54. throw new RuntimeException( "Failed to create service " + name
  55. + ": service constructor threw an exception", ex);
  56. }
  57. startService(service);
  58. return service;
  59. } finally {
  60. Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
  61. }
  62. }
  63. public void startService(@NonNull final SystemService service) {
  64. // Register it.
  65. mServices.add(service);
  66. // Start it.
  67. long time = SystemClock.elapsedRealtime();
  68. try {
  69. service.onStart();
  70. } catch (RuntimeException ex) {
  71. throw new RuntimeException( "Failed to start service " + service.getClass().getName()
  72. + ": onStart threw an exception", ex);
  73. }
  74. warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
  75. }

WifiService:


 
 
  1. public final class WifiService extends SystemService {
  2. private static final String TAG = "WifiService";
  3. final WifiServiceImpl mImpl;
  4. public WifiService(Context context) {
  5. super(context);
  6. mImpl = new WifiServiceImpl(context, new WifiInjector(context), new WifiAsyncChannel(TAG));
  7. }
  8. @Override
  9. public void onStart() {
  10. Log.i(TAG, "Registering " + Context.WIFI_SERVICE);
  11. publishBinderService(Context.WIFI_SERVICE, mImpl);
  12. }

SystemService:


 
 
  1. protected final void publishBinderService(String name, IBinder service) {
  2. publishBinderService(name, service, false);
  3. }
  4. /**
  5. * Publish the service so it is accessible to other services and apps.
  6. */
  7. protected final void publishBinderService(String name, IBinder service,
  8. boolean allowIsolated) {
  9. ServiceManager.addService(name, service, allowIsolated);
  10. }

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

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

 

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

 

 

 

 

2.2.2 Service的WiFi启动流程

先看下WifiServiceImpl流程:


 
 
  1. public class WifiServiceImpl extends IWifiManager.Stub {
  2. /**
  3. * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
  4. * @param enable {@code true} to enable, {@code false} to disable.
  5. * @return {@code true} if the enable/disable operation was
  6. * started or is already in the queue.
  7. */
  8. @Override
  9. public synchronized boolean setWifiEnabled(String packageName, boolean enable)
  10. throws RemoteException {
  11. enforceChangePermission();
  12. Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
  13. + ", uid=" + Binder.getCallingUid() + ", package=" + packageName);
  14. mLog.info( "setWifiEnabled package=% uid=% enable=%").c(packageName)
  15. .c(Binder.getCallingUid()).c(enable).flush();
  16. boolean isFromSettings = checkNetworkSettingsPermission(
  17. Binder.getCallingPid(), Binder.getCallingUid());
  18. // If Airplane mode is enabled, only Settings is allowed to toggle Wifi
  19. if (mSettingsStore.isAirplaneModeOn() && !isFromSettings) {
  20. mLog.info( "setWifiEnabled in Airplane mode: only Settings can enable wifi").flush();
  21. return false;
  22. }
  23. // If SoftAp is enabled, only Settings is allowed to toggle wifi
  24. boolean apEnabled =
  25. mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;
  26. if (apEnabled && !isFromSettings) {
  27. mLog.info( "setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
  28. return false;
  29. }
  30. /*
  31. * Caller might not have WRITE_SECURE_SETTINGS,
  32. * only CHANGE_WIFI_STATE is enforced
  33. */
  34. long ident = Binder.clearCallingIdentity();
  35. try {
  36. if (! mSettingsStore.handleWifiToggled(enable)) {
  37. // Nothing to do if wifi cannot be toggled
  38. return true;
  39. }
  40. } finally {
  41. Binder.restoreCallingIdentity(ident);
  42. }
  43. if (mPermissionReviewRequired) {
  44. final int wiFiEnabledState = getWifiEnabledState();
  45. if (enable) {
  46. if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING
  47. || wiFiEnabledState == WifiManager.WIFI_STATE_DISABLED) {
  48. if (startConsentUi(packageName, Binder.getCallingUid(),
  49. WifiManager.ACTION_REQUEST_ENABLE)) {
  50. return true;
  51. }
  52. }
  53. } else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING
  54. || wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) {
  55. if (startConsentUi(packageName, Binder.getCallingUid(),
  56. WifiManager.ACTION_REQUEST_DISABLE)) {
  57. return true;
  58. }
  59. }
  60. }
  61. mWifiController.sendMessage(CMD_WIFI_TOGGLED);
  62. return true;
  63. }
mWifiController.sendMessage(CMD_WIFI_TOGGLED); return true; }

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


 
 
  1. private void persistWifiState(int state) {
  2. final ContentResolver cr = mContext.getContentResolver();
  3. mPersistWifiState = state;
  4. Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);
  5. }

 
 
  1. /* Values tracked in Settings.Global.WIFI_ON */
  2. static final int WIFI_DISABLED = 0;
  3. static final int WIFI_ENABLED = 1;
  4. /* Wifi enabled while in airplane mode */
  5. private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
  6. /* Wifi disabled due to airplane mode on */
  7. private static final int WIFI_DISABLED_AIRPLANE_ON = 3;
  8. public synchronized boolean handleWifiToggled(boolean wifiEnabled) {
  9. // Can Wi-Fi be toggled in airplane mode ?
  10. if (mAirplaneModeOn && !isAirplaneToggleable()) {
  11. return false;
  12. }
  13. if (wifiEnabled) {
  14. if (mAirplaneModeOn) {
  15. persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE);
  16. } else {
  17. persistWifiState(WIFI_ENABLED);
  18. }
  19. } else {
  20. // When wifi state is disabled, we do not care
  21. // if airplane mode is on or not. The scenario of
  22. // wifi being disabled due to airplane mode being turned on
  23. // is handled handleAirplaneModeToggled()
  24. persistWifiState(WIFI_DISABLED);
  25. }
  26. return true;
  27. }

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

初始化逻辑如下:


 
 
  1. addState(mDefaultState);
  2. addState(mApStaDisabledState, mDefaultState);
  3. addState(mStaEnabledState, mDefaultState);
  4. addState(mDeviceActiveState, mStaEnabledState);
  5. addState(mDeviceInactiveState, mStaEnabledState);
  6. addState(mScanOnlyLockHeldState, mDeviceInactiveState);
  7. addState(mFullLockHeldState, mDeviceInactiveState);
  8. addState(mFullHighPerfLockHeldState, mDeviceInactiveState);
  9. addState(mNoLockHeldState, mDeviceInactiveState);
  10. addState(mStaDisabledWithScanState, mDefaultState);
  11. addState(mApEnabledState, mDefaultState);
  12. addState(mEcmState, mDefaultState);

 

 

 

2.2.3 WifiController

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


 
 
  1. class ApStaDisabledState extends State {
  2. private int mDeferredEnableSerialNumber = 0;
  3. private boolean mHaveDeferredEnable = false;
  4. private long mDisabledTimestamp;
  5. @Override
  6. public void enter() {
  7. mWifiStateMachine.setSupplicantRunning( false);
  8. // Supplicant can't restart right away, so not the time we switched off
  9. mDisabledTimestamp = SystemClock.elapsedRealtime();
  10. mDeferredEnableSerialNumber++;
  11. mHaveDeferredEnable = false;
  12. mWifiStateMachine.clearANQPCache();
  13. }
  14. @Override
  15. public boolean processMessage(Message msg) {
  16. switch (msg.what) {
  17. case CMD_WIFI_TOGGLED:
  18. case CMD_AIRPLANE_TOGGLED:
  19. if (mSettingsStore.isWifiToggleEnabled()) {
  20. if (doDeferEnable(msg)) {
  21. if (mHaveDeferredEnable) {
  22. // have 2 toggles now, inc serial number an ignore both
  23. mDeferredEnableSerialNumber++;
  24. }
  25. mHaveDeferredEnable = !mHaveDeferredEnable;
  26. break;
  27. }
  28. if (mDeviceIdle == false) {
  29. // wifi is toggled, we need to explicitly tell WifiStateMachine that we
  30. // are headed to connect mode before going to the DeviceActiveState
  31. // since that will start supplicant and WifiStateMachine may not know
  32. // what state to head to (it might go to scan mode).
  33. mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
  34. transitionTo(mDeviceActiveState);
  35. } else {
  36. checkLocksAndTransitionWhenDeviceIdle();
  37. }
  38. } else if (mSettingsStore.isScanAlwaysAvailable()) {
  39. transitionTo(mStaDisabledWithScanState);
  40. }
  41. break;
mSettingsStore.isWifiToggleEnabled()) { if (doDeferEnable(msg)) { if (mHaveDeferredEnable) { // have 2 toggles now, inc serial number an ignore both mDeferredEnableSerialNumber++; } 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);
 
 

 
 
  1. public synchronized boolean isWifiToggleEnabled() {
  2. if (!mCheckSavedStateAtBoot) {
  3. mCheckSavedStateAtBoot = true;
  4. if (testAndClearWifiSavedState()) return true;
  5. }
  6. if (mAirplaneModeOn) {
  7. return mPersistWifiState == WIFI_ENABLED_AIRPLANE_OVERRIDE;
  8. } else {
  9. return mPersistWifiState != WIFI_DISABLED;
  10. }
  11. }

收到消息也不是立刻处理的:


 
 
  1. private boolean doDeferEnable(Message msg) {
  2. long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp;
  3. if (delaySoFar >= mReEnableDelayMillis) {
  4. return false;
  5. }
  6. log( "WifiController msg " + msg + " deferred for " +
  7. (mReEnableDelayMillis - delaySoFar) + "ms");
  8. // need to defer this action.
  9. Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
  10. deferredMsg.obj = Message.obtain(msg);
  11. deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
  12. sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS);
  13. return true;
  14. }
  15. ...
  16. mReEnableDelayMillis = mFacade.getLongSetting(mContext,
  17. Settings.Global.WIFI_REENABLE_DELAY_MS, DEFAULT_REENABLE_DELAY_MS);
  18. /**
  19. * See {@link Settings.Global#WIFI_REENABLE_DELAY_MS}. This is the default value if a
  20. * Settings.Global value is not present. This is the minimum time after wifi is disabled
  21. * we'll act on an enable. Enable requests received before this delay will be deferred.
  22. */
  23. private static final long DEFAULT_REENABLE_DELAY_MS = 500;

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

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


 
 
  1. case CMD_DEFERRED_TOGGLE:
  2. if (msg.arg1 != mDeferredEnableSerialNumber) {
  3. log( "DEFERRED_TOGGLE ignored due to serial mismatch");
  4. break;
  5. }
  6. log( "DEFERRED_TOGGLE handled");
  7. sendMessage((Message)(msg.obj));
  8. break;

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


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

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


 
 
  1. class StaEnabledState extends State {
  2. @Override
  3. public void enter() {
  4. mWifiStateMachine.setSupplicantRunning( true);
  5. }

 


 
 
  1. /* Parent: StaEnabledState */
  2. class DeviceActiveState extends State {
  3. @Override
  4. public void enter() {
  5. mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE);
  6. mWifiStateMachine.setHighPerfModeEnabled( false);
  7. }

可以看到其实是调用顺序

 
  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也是一个状态机:


 
 
  1. // CHECKSTYLE:OFF IndentationCheck
  2. addState(mDefaultState);
  3. addState(mInitialState, mDefaultState);
  4. addState(mSupplicantStartingState, mDefaultState);
  5. addState(mSupplicantStartedState, mDefaultState);
  6. addState(mScanModeState, mSupplicantStartedState);
  7. addState(mConnectModeState, mSupplicantStartedState);
  8. addState(mL2ConnectedState, mConnectModeState);
  9. addState(mObtainingIpState, mL2ConnectedState);
  10. addState(mConnectedState, mL2ConnectedState);
  11. addState(mRoamingState, mL2ConnectedState);
  12. addState(mDisconnectingState, mConnectModeState);
  13. addState(mDisconnectedState, mConnectModeState);
  14. addState(mWpsRunningState, mConnectModeState);
  15. addState(mWaitForP2pDisableState, mSupplicantStartedState);
  16. addState(mSupplicantStoppingState, mDefaultState);
  17. addState(mSoftApState, mDefaultState);
  18. // CHECKSTYLE:ON IndentationCheck

 

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

 

1、3)setOperationalMode:


 
 
  1. /**
  2. * Track the state of Wifi connectivity. All event handling is done here,
  3. * and all changes in connectivity state are initiated here.
  4. *
  5. * Wi-Fi now supports three modes of operation: Client, SoftAp and p2p
  6. * In the current implementation, we support concurrent wifi p2p and wifi operation.
  7. * The WifiStateMachine handles SoftAp and Client operations while WifiP2pService
  8. * handles p2p operation.
  9. *
  10. * @hide
  11. */
  12. public class WifiStateMachine extends StateMachine implements WifiNative.WifiRssiEventHandler,
  13. WifiMulticastLockManager. FilterController {

 
 
  1. /**
  2. * TODO: doc
  3. */
  4. public void setOperationalMode(int mode) {
  5. if (mVerboseLoggingEnabled) log( "setting operational mode to " + String.valueOf(mode));
  6. sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
  7. })

2)setSupplicantRunning

    /**
 
 

 
 
  1. * TODO: doc
  2. */
  3. public void setSupplicantRunning(boolean enable) {
  4. if (enable) {
  5. sendMessage(CMD_START_SUPPLICANT);
  6. } else {
  7. sendMessage(CMD_STOP_SUPPLICANT);
  8. }
  9. }

4)  setHighPerfModeEnabled


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

 

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

 


 
 
  1. class InitialState extends State {
  2. private void cleanup() {
  3. // Tearing down the client interfaces below is going to stop our supplicant.
  4. mWifiMonitor.stopAllMonitoring();
  5. mDeathRecipient.unlinkToDeath();
  6. mWifiNative.tearDown();
  7. }
  8. @Override
  9. public void enter() {
  10. mWifiStateTracker.updateState(WifiStateTracker.INVALID);
  11. cleanup();
  12. }
  13. @Override
  14. public boolean processMessage(Message message) {
  15. logStateAndMessage(message, this);
  16. switch (message.what) {
  17. case CMD_START_SUPPLICANT:
  18. Pair<Integer, IClientInterface> statusAndInterface =
  19. mWifiNative.setupForClientMode();
  20. if (statusAndInterface.first == WifiNative.SETUP_SUCCESS) {
  21. mClientInterface = statusAndInterface.second;
  22. } else {
  23. incrementMetricsForSetupFailure(statusAndInterface.first);
  24. }
  25. if (mClientInterface == null
  26. || !mDeathRecipient.linkToDeath(mClientInterface.asBinder())) {
  27. setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
  28. cleanup();
  29. break;
  30. }
  31. try {
  32. // A runtime crash or shutting down AP mode can leave
  33. // IP addresses configured, and this affects
  34. // connectivity when supplicant starts up.
  35. // Ensure we have no IP addresses before a supplicant start.
  36. mNwService.clearInterfaceAddresses(mInterfaceName);
  37. // Set privacy extensions
  38. mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
  39. // IPv6 is enabled only as long as access point is connected since:
  40. // - IPv6 addresses and routes stick around after disconnection
  41. // - kernel is unaware when connected and fails to start IPv6 negotiation
  42. // - kernel can start autoconfiguration when 802.1x is not complete
  43. mNwService.disableIpv6(mInterfaceName);
  44. } catch (RemoteException re) {
  45. loge( "Unable to change interface settings: " + re);
  46. } catch (IllegalStateException ie) {
  47. loge( "Unable to change interface settings: " + ie);
  48. }
  49. if (!mWifiNative.enableSupplicant()) {
  50. loge( "Failed to start supplicant!");
  51. setWifiState(WifiManager.WIFI_STATE_UNKNOWN);
  52. cleanup();
  53. break;
  54. }
  55. if (mVerboseLoggingEnabled) log( "Supplicant start successful");
  56. mWifiMonitor.startMonitoring(mInterfaceName, true);
  57. mWifiInjector.getWifiLastResortWatchdog().clearAllFailureCounts();
  58. setSupplicantLogLevel();
  59. transitionTo(mSupplicantStartingState);
  60. break;
  61. case CMD_START_AP:
  62. transitionTo(mSoftApState);
  63. break;
  64. case CMD_SET_OPERATIONAL_MODE:
  65. mOperationalMode = message.arg1;
  66. if (mOperationalMode != DISABLED_MODE) {
  67. sendMessage(CMD_START_SUPPLICANT);
  68. }
  69. break;
  70. default:
  71. return NOT_HANDLED;
  72. }
  73. return HANDLED;
  74. }
  75. }

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


 
 
  1. class ScanModeState extends State {
  2. private int mLastOperationMode;
  3. @Override
  4. public void enter() {
  5. mLastOperationMode = mOperationalMode;
  6. mWifiStateTracker.updateState(WifiStateTracker.SCAN_MODE);
  7. }
  8. @Override
  9. public boolean processMessage(Message message) {
  10. logStateAndMessage(message, this);
  11. switch(message.what) {
  12. case CMD_SET_OPERATIONAL_MODE:
  13. if (message.arg1 == CONNECT_MODE) {
  14. mOperationalMode = CONNECT_MODE;
  15. setWifiState(WIFI_STATE_ENABLING);
  16. transitionTo(mDisconnectedState);
  17. } else if (message.arg1 == DISABLED_MODE) {
  18. transitionTo(mSupplicantStoppingState);
  19. }
  20. // Nothing to do
  21. break;
  22. // Handle scan. All the connection related commands are
  23. // handled only in ConnectModeState
  24. case CMD_START_SCAN:
  25. handleScanRequest(message);
  26. break;
  27. default:
  28. return NOT_HANDLED;
  29. }
  30. return HANDLED;
  31. }
  32. }

 

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

 

 

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

PS:


 
 
  1. /**
  2. * Enable wpa_supplicant via wificond.
  3. * @return Returns true on success.
  4. */
  5. public boolean enableSupplicant() {
  6. return mWificondControl.enableSupplicant();
  7. }

 
 
  1. /**
  2. * Start Monitoring for wpa_supplicant events.
  3. *
  4. * @param iface Name of iface.
  5. * TODO: Add unit tests for these once we remove the legacy code.
  6. */
  7. public synchronized void startMonitoring(String iface, boolean isStaIface) {
  8. if (ensureConnectedLocked()) {
  9. setMonitoring(iface, true);
  10. broadcastSupplicantConnectionEvent(iface);
  11. } else {
  12. boolean originalMonitoring = isMonitoring(iface);
  13. setMonitoring(iface, true);
  14. broadcastSupplicantDisconnectionEvent(iface);
  15. setMonitoring(iface, originalMonitoring);
  16. Log.e(TAG, "startMonitoring(" + iface + ") failed!");
  17. }
  18. }

 

 

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

 

 


 
 
  1. case CMD_SET_OPERATIONAL_MODE:
  2. messageHandlingStatus = MESSAGE_HANDLING_STATUS_DEFERRED;
  3. deferMessage( message);
  4. break;

至于第4步

SupplicantStartedState状态会处理:


 
 
  1. case CMD_SET_HIGH_PERF_MODE:
  2. if (message.arg1 == 1) {
  3. setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, false);
  4. } else {
  5. setSuspendOptimizations(SUSPEND_DUE_TO_HIGH_PERF, true);
  6. }
  7. break;

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


 
 
  1. private void setSuspendOptimizationsNative(int reason, boolean enabled) {
  2. if (mVerboseLoggingEnabled) {
  3. log( "setSuspendOptimizationsNative: " + reason + " " + enabled
  4. + " -want " + mUserWantsSuspendOpt. get()
  5. + " stack:" + Thread.currentThread().getStackTrace()[ 2].getMethodName()
  6. + " - " + Thread.currentThread().getStackTrace()[ 3].getMethodName()
  7. + " - " + Thread.currentThread().getStackTrace()[ 4].getMethodName()
  8. + " - " + Thread.currentThread().getStackTrace()[ 5].getMethodName());
  9. }
  10. //mWifiNative.setSuspendOptimizations(enabled);
  11. if (enabled) {
  12. mSuspendOptNeedsDisabled &= ~reason;
  13. /* None of dhcp, screen or highperf need it disabled and user wants it enabled */
  14. if (mSuspendOptNeedsDisabled == 0 && mUserWantsSuspendOpt. get()) {
  15. if (mVerboseLoggingEnabled) {
  16. log( "setSuspendOptimizationsNative do it " + reason + " " + enabled
  17. + " stack:" + Thread.currentThread().getStackTrace()[ 2].getMethodName()
  18. + " - " + Thread.currentThread().getStackTrace()[ 3].getMethodName()
  19. + " - " + Thread.currentThread().getStackTrace()[ 4].getMethodName()
  20. + " - " + Thread.currentThread().getStackTrace()[ 5].getMethodName());
  21. }
  22. mWifiNative.setSuspendOptimizations( true);
  23. }
  24. } else {
  25. mSuspendOptNeedsDisabled |= reason;
  26. mWifiNative.setSuspendOptimizations( false);
  27. }
  28. }

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

继续梳理见

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

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

 

3. 总结

关注公众号,获取更多开发必备知识
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值