[Android]Android P(9) WIFI学习笔记 - Framework (1)

[Android]Android P(9) WIFI学习笔记 - Framework (1)

前言

  1. 基于Android P源码学习;
  2. 代码片为了方便阅读段经过删、裁减,请以实际源码为准;

初始化流程

  1. SystemServer在调用到startOtherServices时,会通过
mSystemServiceManager.startService(WIFI_SERVICE_CLASS);

启动WIFI的SystemService,对应类为:

com.android.server.wifi.WifiService
  1. 构造WifiService时会同时构造出WifiServiceImpl
    public WifiService(Context context) {
        super(context);
        mImpl = new WifiServiceImpl(context, new WifiInjector(context), new WifiAsyncChannel(TAG));
    }

并在onStart的回调中将构造出的WifiServiceImpl对象注册到SystemService的表中;

    @Override
    public void onStart() {
        publishBinderService(Context.WIFI_SERVICE, mImpl);
    }

WifiServiceImplIWifiManager.Stub的实现类,因此WifiServiceImplWifiManager大部分方法调用的JAVA层实现、表达:

    public class WifiServiceImpl extends IWifiManager.Stub {
        ...
    }
  1. WIFI相关服务的API通过WifiManager暴露给App调用,而WifiManager的构造是在SystemServiceRegistry的静态代码块中注册的回调,并在第一次调用getSystemService(Context.WIFI_SERVICE)时进行懒加载(构造);
    registerService(Context.WIFI_SERVICE, WifiManager.class,
            new CachedServiceFetcher<WifiManager>() {
        @Override
        public WifiManager createService(ContextImpl ctx) throws ServiceNotFoundException {
            IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SERVICE);
            IWifiManager service = IWifiManager.Stub.asInterface(b);
            return new WifiManager(ctx.getOuterContext(), service,
                    ConnectivityThread.getInstanceLooper());
        }});

时序图如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sFoFutWK-1624610672006)(WIFI_Framework_Init_Flow.png)]

常用方法

public boolean setWifiEnabled(boolean enabled);
public int getWifiState();
public boolean isWifiEnabled();
public void connect(int networkId, ActionListener listener);
@SystemApi
public void connect(WifiConfiguration config, ActionListener listener);
...
(TO BE UPDATED)

调用栈

WifiManager.setWifiEnabled()为例:

    public boolean setWifiEnabled(boolean enabled) {
        try {
            return mService.setWifiEnabled(mContext.getOpPackageName(), enabled);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

1. 通过Binder调用到IWifiManager实例(即WifiServiceImpl)的setWifiEnabled方法:

    @Override
    public synchronized boolean setWifiEnabled(String packageName, boolean enable)
            throws RemoteException {
        if (enforceChangePermission(packageName) != MODE_ALLOWED) {
            return false;
        }

        boolean isFromSettings = checkNetworkSettingsPermission(
                Binder.getCallingPid(), Binder.getCallingUid());

        // If Airplane mode is enabled, only Settings is allowed to toggle Wifi
        if (mSettingsStore.isAirplaneModeOn() && !isFromSettings) {
            return false;
        }

        // If SoftAp is enabled, only Settings is allowed to toggle wifi
        boolean apEnabled = mWifiApState == WifiManager.WIFI_AP_STATE_ENABLED;

        if (apEnabled && !isFromSettings) {
            return false;
        }

        /*
        * Caller might not have WRITE_SECURE_SETTINGS,
        * only CHANGE_WIFI_STATE is enforced
        */
        long ident = Binder.clearCallingIdentity();
        try {
            if (! mSettingsStore.handleWifiToggled(enable)) {
                // Nothing to do if wifi cannot be toggled
                return true;
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }


        if (mPermissionReviewRequired) {
            final int wiFiEnabledState = getWifiEnabledState();
            if (enable) {
                if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING
                        || wiFiEnabledState == WifiManager.WIFI_STATE_DISABLED) {
                    if (startConsentUi(packageName, Binder.getCallingUid(),
                            WifiManager.ACTION_REQUEST_ENABLE)) {
                        return true;
                    }
                }
            } else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING
                    || wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) {
                if (startConsentUi(packageName, Binder.getCallingUid(),
                        WifiManager.ACTION_REQUEST_DISABLE)) {
                    return true;
                }
            }
        }

        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
        return true;
    }

整个方法中,除去权限、状态检查等,真正执行WIFI开关的只有如下两个地方:
mSettingsStore.handleWifiToggled(enable);
mWifiController.sendMessage(CMD_WIFI_TOGGLED);

mSettingsStoreWifiSettingsStore的实例,由WifiServiceImpl构造时通过mWifiInjector.getWifiSettingsStore()获取; mWifiInjectorWifiInjector的实例,同样由WifiServiceImpl构造时传入;

注意:WifiInjector为单例设计,此处为首次构造,其余部分仅能通过WifiInjector.getInstance()获取;

而回到mSettingsStore.handleWifiToggled()这句调用本身。其本质只是在判断了当前设备是否处于飞行模式,从而将不同状态写入到Settings.Global中:

	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 {
	        persistWifiState(WIFI_DISABLED);
	    }
	    return true;
	}
	
	private void persistWifiState(int state) {
	    final ContentResolver cr = mContext.getContentResolver();
	    mPersistWifiState = state;
	    Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state);
	}

至于mWifiController,则是负责处理WIFI行为的控制器,系WifiServiceImplWifiStateMachine的交互中间件;

mSettingsStore变量一样,mWifiController同样是由mInjector提供;

WifiController继承自StateMachine,关于StateMachine的更多信息,详见:

内部维护了如下几种State,其层级关系如图:

在这里插入图片描述
2. StateMachine是以State为驱动的状态机,在处于不同State时,向StateMachine发送不同的消息,可以得到不同的响应;

因此,要确认这里mWifiController.sendMessage(CMD_WIFI_TOGGLED);的具体实现,就需要先确认现在工作的State:

    if (checkScanOnlyModeAvailable()) {
        setInitialState(mStaDisabledWithScanState);
    } else {
        setInitialState(mStaDisabledState);
    }

可见WifiController的初始状态为StaDisabledWithScanStateStaDisabledState(取决于是否开启“WIFI始终扫描”选项)

Android P上默认没有开启“WIFI始终扫描”,因此初始状态为StaDisabledState

那么查看StaDisabledStateprocessMessage可以看到,处理CMD_WIFI_TOGGLED消息的逻辑如下:

    @Override
    public boolean processMessage(Message msg) {
        switch (msg.what) {
            case CMD_WIFI_TOGGLED:
                //读取刚才mSettingsStore设置的键值对,因为这里是StaDisabledState,所以不需要处理
                //disable的消息,只需专注于enable即可;
                if (mSettingsStore.isWifiToggleEnabled()) {
                    if (doDeferEnable(msg)) {
                        if (mHaveDeferredEnable) {
                            //此时表示有两个延时enable发送了,需要再让计数自增
                            //使之前发送的msg无效;
                            mDeferredEnableSerialNumber++;
                        }
                        mHaveDeferredEnable = !mHaveDeferredEnable;
                        //如果要发送延迟消息,则此次不切换状态
                        break;
                    }
                    //由于当前方法调用栈在handleMessage中,且早于performTransitions,
                    //因此此处transitionTo调用后会立即调用StaDisabledState的exit与
                    //DeviceActiveState的enter方法
                    transitionTo(mDeviceActiveState);

                } else if (checkScanOnlyModeAvailable()) {
                    // only go to scan mode if we aren't in airplane mode
                    if (mSettingsStore.isAirplaneModeOn()) {
                        transitionTo(mStaDisabledWithScanState);
                    }
                }
                break;
            ...
            case CMD_DEFERRED_TOGGLE:
                //如果检测到延时过程中发送了两个enable消息,mDeferredEnableSerialNumber
                //检测不匹配;则不进行任何操作
                if (msg.arg1 != mDeferredEnableSerialNumber) {
                    break;
                }
                //重发CMD_WIFI_TOGGLED,并执行上方transitionTo(mDeviceActiveState)的逻辑
                sendMessage((Message)(msg.obj));
                break;
            ...
        }
        return HANDLED;
    }

由于快速开关WIFI开关可能会导致上下层的状态紊乱,因此doDeferEnable方法就是用于给快速开关WIFI开关的场景添加一个延时:

    private boolean doDeferEnable(Message msg) {
        long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp;
        //mReEnableDelayMillis默认500ms,可通过WIFI_REENABLE_DELAY_MS修改
        if (delaySoFar >= mReEnableDelayMillis) {
            //如果距离上次disable已经过去一段时间,则无需延时操作
            return false;
        }
        ...

        //注意,此处返回值恒为true,因此返回到processMessage后不会执行transitionTo
        //因此负责处理CMD_DEFERRED_TOGGLE消息的还是StaDisabledState.
        Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE);
        deferredMsg.obj = Message.obtain(msg);
        //这个是一个自增的计数,用来保证一些消息处理的时序,通过msg传递给下一个State
        deferredMsg.arg1 = ++mDeferredEnableSerialNumber;
        //以mReEnableDelayMillis默认500ms为例,此处确保延时从上次disable开始500+5ms
        sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS);
        return true;
    }

可以看到,无论是否进行消息延时,最终都会通过切换State到DeviceActiveState,并调用其enter()方法:

    class DeviceActiveState extends State {
        @Override
        public void enter() {
            mWifiStateMachinePrime.enterClientMode();
            mWifiStateMachine.setHighPerfModeEnabled(false);
        }
        ...
    }

这里牵扯到了WifiStateMachinePrimeWifiStateMachine两个类:

  • WifiStateMachinePrime内部维护了一个ModeStateMachine继承自StateMachine
  • WifiStateMachine直接继承自StateMachine

注意:

  • WifiStateMachinePrimeWifiStateMachine两个类的构造方法中,使用第三个参数(即wifiStateMachineLooper)作为SmHandler构造的Looper
  • WifiController使用的是第五个参数(即mWifiServiceHandlerThread.getLooper());
  • 因此WifiStateMachinePrimeWifiStateMachineSmHandler工作在同一线程,WifiControllerSmHandler工作在WifiServiceHandlerThread线程上;
    mWifiStateMachine = new WifiStateMachine(mContext, mFrameworkFacade,
            wifiStateMachineLooper, UserManager.get(mContext),
            this, mBackupManagerProxy, mCountryCode, mWifiNative,
            new WrongPasswordNotifier(mContext, mFrameworkFacade),
            mSarManager);
    mWifiStateMachinePrime = new WifiStateMachinePrime(this, mContext, wifiStateMachineLooper,
            mWifiNative, new DefaultModeManager(mContext, wifiStateMachineLooper),
            mBatteryStats);
    ...
    mWifiController = new WifiController(mContext, mWifiStateMachine, wifiStateMachineLooper,
            mSettingsStore, mWifiServiceHandlerThread.getLooper(), mFrameworkFacade,
            mWifiStateMachinePrime);

WifiStateMachine负责处理WIFI的Client模式(即STA模式)下各个状态的切换,其内部的State层级关系如下图:

在这里插入图片描述

WifiStateMachinePrime目前根据注释可知,还处于WIP阶段(Work In Progress),待重构后,会用来替代WifiStateMachine

WifiStateMachinePrime内部的ModeStateMachine管理了三种状态,且三者并列,没有层级关系:

  • ClientModeActiveState
  • ScanOnlyModeActiveState
  • WifiDisabledState

初始状态为WifiDisabledState

回到WifiController中的DeviceActiveState.enter()方法:

    class DeviceActiveState extends State {
        @Override
        public void enter() {
            mWifiStateMachinePrime.enterClientMode();
            mWifiStateMachine.setHighPerfModeEnabled(false);
        }
        ...
    }

WifiStateMachinePrime.enterClientMode()方法用于切换WifiStateMachinePrime内部ModeStateMachine的状态到ModeStateMachine.CMD_START_CLIENT_MODE
以默认状态WifiDisabledState为例,会在processMessage方法中走到如下这里:

    private boolean checkForAndHandleModeChange(Message message) {
        switch(message.what) {
            case ModeStateMachine.CMD_START_CLIENT_MODE:
                mModeStateMachine.transitionTo(mClientModeActiveState);
                break;
            ...
            default:
                return NOT_HANDLED;
        }
        return HANDLED;
    }

从而状态切换到ClientModeActiveState

继续跟踪ClientModeActiveStateenter方法,可以发现这里通过WifiInjector构造了一个ClientModeManager

class ClientModeActiveState extends ModeActiveState {
            @Override
            public void enter() {
                mListener = new ClientListener();
                mManager = mWifiInjector.makeClientModeManager(mListener);
                mManager.start();
                mActiveModeManagers.add(mManager);
                updateBatteryStatsWifiState(true);
            }

            ClientListener mListener;
            private class ClientListener implements ClientModeManager.Listener {
                @Override
                public void onStateChanged(int state) {
                    ...
                    if (state == WifiManager.WIFI_STATE_UNKNOWN) {
                        mModeStateMachine.sendMessage(CMD_CLIENT_MODE_FAILED, this);
                    } else if (state == WifiManager.WIFI_STATE_DISABLED) {
                        mModeStateMachine.sendMessage(CMD_CLIENT_MODE_STOPPED, this);
                    } else if (state == WifiManager.WIFI_STATE_ENABLED) {
                    }
                    ...
                }
            }
            ...
}

ClientModeManager的构造方法中构造了一个ClientModeStateMachine,后者又是一个StateMachine的子类。
不过这个状态机比较简单,只有两个状态:

  • IdleState
  • StartedState

初始状态是IdleState
ClientModeStateMachine的构造方法中调用了start()方法,因而直接进入IdleState,并执行IdleState的enter方法:

    private class IdleState extends State {

        @Override
        public void enter() {
            mClientInterfaceName = null;
            mIfaceIsUp = false;
        }
        ...
    }

执行完ClientModeStateMachine的构造方法后,ClientModeManager的构造方法也就结束了,实例对象通过WifiInjector.makeClientModeManager()返回;
随后调用ClientModeManagerenter()方法:

注意,ClientModeManager本身并非继承StateMachine,而是实现了ActiveModeManager接口,实现了单独的start()方法,而非StateMachinestart()方法,注意区分

    public void start() {
        mStateMachine.sendMessage(ClientModeStateMachine.CMD_START);
    }

发送CMD_START到当前状态,即:IdleState

@Override
        public boolean processMessage(Message message) {
            switch (message.what) {
                case CMD_START:
                    updateWifiState(WifiManager.WIFI_STATE_ENABLING,
                                    WifiManager.WIFI_STATE_DISABLED);
                    String hostname = Settings.Global.getString(mContext.getContentResolver(), Settings.Global.DEVICE_NAME);
                    SystemProperties.set("net.hostname", hostname);
                    mClientInterfaceName = mWifiNative.setupInterfaceForClientMode(
                            false /* not low priority */, mWifiNativeInterfaceCallback);
                    if (TextUtils.isEmpty(mClientInterfaceName)) {
                        updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
                                        WifiManager.WIFI_STATE_ENABLING);
                        updateWifiState(WifiManager.WIFI_STATE_DISABLED,
                                        WifiManager.WIFI_STATE_UNKNOWN);
                        break;
                    }
                    sendScanAvailableBroadcast(false);
                    mScanRequestProxy.enableScanningForHiddenNetworks(false);
                    mScanRequestProxy.clearScanResults();
                    transitionTo(mStartedState);
                    break;
                default:
                    return NOT_HANDLED;
            }
            return HANDLED;
        }

其中重点关注如下几个方法:

updateWifiState(WifiManager.WIFI_STATE_ENABLING, WifiManager.WIFI_STATE_DISABLED);
mWifiNative.setupInterfaceForClientMode(false, mWifiNativeInterfaceCallback)
sendScanAvailableBroadcast(false);
mScanRequestProxy.enableScanningForHiddenNetworks(false);
mScanRequestProxy.clearScanResults();
transitionTo(mStartedState);

updateWifiState方法主要用于处理状态的回调,以及广播的发送:

    private void updateWifiState(int newState, int currentState) {
        if (!mExpectedStop) {
            mListener.onStateChanged(newState);
        }

        //状态异常时标记,后续updateWifiState则不会再执行mListener的onStateChanged回调
        if (newState == WifiManager.WIFI_STATE_UNKNOWN
                || newState == WifiManager.WIFI_STATE_DISABLED) {
            mExpectedStop = true;
        }

        //状态未知时不发送广播
        if (newState == WifiManager.WIFI_STATE_UNKNOWN) {
            return;
        }

        //通知WifiStateMachine同步状态
        mWifiStateMachine.setWifiStateForApiCalls(newState);

        //发送WIFI_STATE_CHANGED_ACTION广播
        final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        intent.putExtra(WifiManager.EXTRA_WIFI_STATE, newState);
        intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, currentState);
        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }

sendScanAvailableBroadcast(false)表示发送WIFI_SCAN_AVAILABLE广播,且EXTRA_SCAN_AVAILABLE的值为WIFI_STATE_DISABLED

    private void sendScanAvailableBroadcast(boolean available) {
        final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        if (available) {
            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_ENABLED);
        } else {
            intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED);
        }
        mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }

mScanRequestProxy.enableScanningForHiddenNetworks(false)表示通知ScanRequestProxy设置成员变量mScanRequestProxy,以停用隐藏网络扫描功能:

    public void enableScanningForHiddenNetworks(boolean enable) {
        mScanningForHiddenNetworksEnabled = enable;
    }

mScanRequestProxy.clearScanResults()则是清空已经缓存的扫描结果:

    public void clearScanResults() {
        mLastScanResults.clear();
        mLastScanTimestampForBgApps = 0;
        mLastScanTimestampsForFgApps.clear();
    }

mWifiNative.setupInterfaceForClientMode方法则会与HAL(supplicant)交互,会在下一章节继续分析;

如果所有调用正常,最后会调用transitionTo(mStartedState)进行状态切换:

    private class StartedState extends State {

        private void onUpChanged(boolean isUp) {
            if (isUp == mIfaceIsUp) {
                return;  // no change
            }
            mIfaceIsUp = isUp;
            if (isUp) {
                sendScanAvailableBroadcast(true);
                mWifiStateMachine.setOperationalMode(WifiStateMachine.CONNECT_MODE,
                                                        mClientInterfaceName);
                updateWifiState(WifiManager.WIFI_STATE_ENABLED,
                                WifiManager.WIFI_STATE_ENABLING);
            } else {
                if (mWifiStateMachine.isConnectedMacRandomizationEnabled()) {
                    return;
                }
                updateWifiState(WifiManager.WIFI_STATE_UNKNOWN,
                                WifiManager.WIFI_STATE_ENABLED);
                mStateMachine.sendMessage(CMD_INTERFACE_DOWN);
            }
        }
        public void enter() {
            mIfaceIsUp = false;
            onUpChanged(mWifiNative.isInterfaceUp(mClientInterfaceName));
            mScanRequestProxy.enableScanningForHiddenNetworks(true);
        }
        ...
    }

如果之前mWifiNative.setupInterfaceForClientMode调用没有异常的话,这里mWifiNative.isInterfaceUp(mClientInterfaceName)为true,因而调用updateWifiState(WifiManager.WIFI_STATE_ENABLED)可完成WIFI开启的整个流程;

最后附上一副总结性质的时序图,其中部分非关键调用已经略去,关键调用加粗显示;

在这里插入图片描述

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Android开发教程及笔记-完整版.pdf》是一本关于Android开发的教程和笔记的完整版电子书。这本电子书主要介绍了Android开发所需的各种知识和技术,对于想要学习Android开发的人来说是一本非常有价值的资料。 这本电子书包含了Android开发的基础知识,如Android系统的介绍、Android开发环境的搭建以及常用开发工具的使用方法。同时,它也详细介绍了Android应用程序的开发流程,包括界面设计、布局管理、事件处理、数据库操作等方面的内容,使读者能够全面掌握Android应用程序的开发技巧。 此外,这本电子书还介绍了一些高级的Android开发技术,如网络编程、多媒体处理、传感器应用等方面的知识。通过学习这些高级技术,读者可以进一步提升自己的Android开发水平,设计出更加优秀和复杂的Android应用程序。 除了知识点的介绍之外,这本电子书还提供了大量的实例和代码,让读者能够通过实践来巩固所学知识。同时,它还给出了一些常见问题的解决方法和开发经验的分享,帮助读者更好地理解和应用所学的知识。 总之,《Android开发教程及笔记-完整版.pdf》是一本非常实用的Android开发学习资料,其全面而详细的内容将帮助读者系统地学习和掌握Android开发的技能,为实际项目的开发提供了很好的指导。无论是初学者还是有一定经验的开发者,都可以从中受益匪浅。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值