1. 程式人生 > >wifi啟動流程簡介一(app 到 framework)

wifi啟動流程簡介一(app 到 framework)

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

“從最表層的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. }

    <