1. 程式人生 > >Wifi服務框架介紹(原)

Wifi服務框架介紹(原)

        本文簡要介紹WIFI服務的主要框架以及運作機制

        WIFI框架主要涉及到以下幾個物件:WifiService、WifiManager、WifiServiceImpl、WifiStateMachine等。下面來介紹這四個物件的內在聯絡。

一、WIFI服務的初始化

        WIFI服務的初始化分為兩個部分,WifiService的初始化和WifiManager的初始化,下面分別介紹。

1.1、WifiService的初始化流程

        WifiService的初始化流程是在SystemService中被啟動的:
        @SystemServer.java
        private static final String WIFI_SERVICE_CLASS = "com.android.server.wifi.WifiService";
        private void startOtherServices() {
            mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
        }
        在這裡通過SystemServiceManager將WIFI的主服務(WifiService)啟動,然後來看該Service的啟動過程:
        @WifiService.java
        public final class WifiService extends SystemService {
            private static final String TAG = "WifiService";
            final WifiServiceImpl mImpl;
            public WifiService(Context context) {
                super(context);
                //建立WifiServiceImpl物件
                mImpl = new WifiServiceImpl(context);
            }
            @Override
            public void onStart() {
                //將WifiServiceImpl註冊到ServiceManager
                publishBinderService(Context.WIFI_SERVICE, mImpl);
            }


            @Override
            public void onBootPhase(int phase) {
                if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
                    mImpl.checkAndStartWifi();
                }
            }
        }
        以上是WifiService的全部內容,其實該Service只完成了兩個任務:
        1、在初始化時,也就是構造方法中,建立WifiServiceImpl物件。
        2、在onStart時,將WifiServiceImpl物件註冊到ServiceManager中。

        這裡建立的WifiServiceImpl是整個WIFI服務的管理者,他負責將客戶端對WIFI的請求分類,然後派發給不同的處理中心。
        下面先來看WifiServiceImpl的屬性:
        public final class WifiServiceImpl extends IWifiManager.Stub {}
        這說明該類是一個服務的實現類。
        然後來看該物件的初始化過程,也就是構造方法:
        @WifiServiceImpl.java
        public WifiServiceImpl(Context context) {
            mContext = context;
            mInterfaceName =  SystemProperties.get("wifi.interface", "wlan0");
            mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName);
            //建立wifi狀態機
            mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName, mTrafficPoller);
            mWifiStateMachine.enableRssiPolling(true);
            //初始化各種管理者
            mBatteryStats = BatteryStatsService.getService();
            mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
            mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
            mSettingsStore = new WifiSettingsStore(mContext);
            HandlerThread wifiThread = new HandlerThread("WifiService");
            wifiThread.start();
            mClientHandler = new ClientHandler(wifiThread.getLooper());
            mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
            mWifiController = new WifiController(mContext, this, wifiThread.getLooper());
            mBatchedScanSupported = mContext.getResources().getBoolean( R.bool.config_wifi_batched_scan_supported);
        }
        在這裡初始化各種與WIFI管理有關的輔助類,其中包含最重要的一個就是WIFI的狀態機WifiStateMachine,他是整個WIFI機制的核心。下面來看該狀態機的初始化流程:
        @WifiStateMachine.java
        public WifiStateMachine(Context context, String wlanInterface, WifiTrafficPoller trafficPoller){
            super("WifiStateMachine");
            mContext = context;
            mInterfaceName = wlanInterface;
            //建立NetworkInfo物件
            mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, "");
            mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( BatteryStats.SERVICE_NAME));
            //建立各種輔助類
            IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
            mNwService = INetworkManagementService.Stub.asInterface(b);
            mP2pSupported = mContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_WIFI_DIRECT);
            mWifiNative = new WifiNative(mInterfaceName);
            mWifiConfigStore = new WifiConfigStore(context, mWifiNative);
            mWifiAutoJoinController = new WifiAutoJoinController(context, this, mWifiConfigStore, mWifiConnectionStatistics, mWifiNative);
            mWifiMonitor = new WifiMonitor(this, mWifiNative);
            mWifiInfo = new WifiInfo();
            ......
            //初始化狀態機
            addState(mDefaultState);
            addState(mInitialState, mDefaultState);
            addState(mSupplicantStartingState, mDefaultState);
            addState(mSupplicantStartedState, mDefaultState);
            addState(mDriverStartingState, mSupplicantStartedState);
            addState(mDriverStartedState, mSupplicantStartedState);
            addState(mScanModeState, mDriverStartedState);
            addState(mConnectModeState, mDriverStartedState);
            addState(mL2ConnectedState, mConnectModeState);
            addState(mObtainingIpState, mL2ConnectedState);
            addState(mVerifyingLinkState, mL2ConnectedState);
            addState(mConnectedState, mL2ConnectedState);
            addState(mRoamingState, mL2ConnectedState);
            addState(mDisconnectingState, mConnectModeState);
            addState(mDisconnectedState, mConnectModeState);
            addState(mWpsRunningState, mConnectModeState);
            addState(mWaitForP2pDisableState, mSupplicantStartedState);
            addState(mDriverStoppingState, mSupplicantStartedState);
            addState(mDriverStoppedState, mSupplicantStartedState);
            addState(mSupplicantStoppingState, mDefaultState);
            addState(mSoftApStartingState, mDefaultState);
            addState(mSoftApStartedState, mDefaultState);
            addState(mTetheringState, mSoftApStartedState);
            addState(mTetheredState, mSoftApStartedState);
            addState(mUntetheringState, mSoftApStartedState);
            //設定狀態機初始模式
            setInitialState(mInitialState);
            //啟動狀態機
            start();
            ......
        }
        我們看到,在WifiStateMachine的初始化過程中建立了大量的輔助類,其中就包括NetworkInfo,他的作用就是標記當前網路的各項屬性,比如當前網路的型別、是否可用、是否處於漫遊等,然後還建立了許多WIFI的狀態機,標識當前WIFI所處的狀態,最後將狀態機初始狀態設定為mInitialState,並將狀態機start。
        以上就是WifiService的全部初始化過程,其主要過程分為以下四個部分:
        1、在SystemServer中啟動WifiService;
        2、在WifiService啟動過程中建立並初始化WifiServiceImpl;
        3、在WifiServiceImpl初始化過程中建立並初始化WifiStateMachine物件;

        4、在WifiStateMachine初始化過程中建立各種狀態機並啟動他們;

1.2、WifiManager的初始化流程

        WIFI框架還有另外一個初始化流程實在ContextImpl中進行的。
        當系統初始化時,會在Context物件的實現類ContextImpl中註冊一些常用的服務,這樣就可以在應用內部通過Context物件的getSystemService()方法來獲取相應的服務。而WIFI在ContextImpl中註冊了WifiManager用於向一般應用提供WIFI的服務:
        @ContextImpl.java
        registerService(WIFI_SERVICE, new ServiceFetcher() {
            public Object createService(ContextImpl ctx) {
                IBinder b = ServiceManager.getService(WIFI_SERVICE);
                IWifiManager service = IWifiManager.Stub.asInterface(b);
                return new WifiManager(ctx.getOuterContext(), service);
            }});
        從這裡可以知道兩個資訊:
        1、應用可以通過Context物件的getSystemService(Context.WIFI_SERVICE)的方法獲取到一個WifiManager的物件用於控制WIFI;
        2、WifiManager的建立需要使用ServiceManager的WIFI_SERVICE服務,而這個WIFI_SERVICE就是在WifiService中註冊的WifiServiceImpl物件;

        下面來看WifiManager的建立過程:
        @WifiManager.java
        public WifiManager(Context context, IWifiManager service) {
            mContext = context;
            //這裡的mService就是建立WifiManager時傳遞進來的WifiServiceImpl物件
            mService = service;
            init();
        }
        private void init() {
            synchronized (sThreadRefLock) {
                if (++sThreadRefCount == 1) {
                    //獲取WifiServiceImpl中的Messenger物件
                    Messenger messenger = getWifiServiceMessenger();
                    if (messenger == null) {
                        sAsyncChannel = null;
                        return;
                    }
                    //建立AsyncChannel通道
                    sHandlerThread = new HandlerThread("WifiManager");
                    sAsyncChannel = new AsyncChannel();
                    sConnected = new CountDownLatch(1);
                    sHandlerThread.start();
                    Handler handler = new ServiceHandler(sHandlerThread.getLooper());
                    //與WifiServiceImpl申請建立單向AsyncChannel
                    sAsyncChannel.connect(mContext, handler, messenger);
                    try {
                        sConnected.await();
                    } catch (InterruptedException e) {
                        Log.e(TAG, "interrupted wait at init");
                    }
                }
            }
        }
        從上面WifiManager的初始化過程中我們看到,其初始化的過程中完成了以下兩個任務:
        1、用WifiServiceImpl初始化mService物件;
        2、向WifiServiceImpl申請單向的AsyncChannel(想要連線AsyncChannel請點選這裡);

        至此,WIFI框架就完成了所有需要初始化的動作,我們用一張流程圖來標識該過程:


二、WIFI服務的運作機制

        由於應用操作WIFI是通過WifiManager進行的,那麼我們可以從WifiManager開始來查詢訊息在WIFI內部的傳遞機制。
        以下是WifiManager提供的幾個比較重要的對外介面:
        //獲取所有網路連線
        public List<WifiConfiguration> getConfiguredNetworks() {}
        //新增網路連線
        public int addNetwork(WifiConfiguration config) {}
        //更新網路連線
        public int updateNetwork(WifiConfiguration config) {}
        //是否支援5Ghz
        public boolean is5GHzBandSupported() {}
        //是否支援WIFI熱點
        public boolean isPortableHotspotSupported() {}
        //開啟關閉WIFI
        public boolean setWifiEnabled(boolean enabled) {}
        //連線某個WIFI
        public void connect(int networkId, ActionListener listener) {}
        //斷開當前連線
        public boolean disconnect() {}
        //新增黑名單
        public boolean addToBlacklist(String bssid) {}
        //清除黑名單
        public boolean clearBlacklist() {}
        我們挑選兩個比較典型的方法進行跟蹤,分別是:控制WIFI開關的setWifiEnabled()和連線某個WIFI的connect()方法。

        為什麼要挑選這兩個方法呢?是因為這兩個方法分別使用兩種方式與WifiService進行通訊

2.1、setWifiEnabled方式

        在該方式中,WifiManager通過直接呼叫的方式與WifiServiceImpl進行通訊。
        @WifiManager.java
        public boolean setWifiEnabled(boolean enabled) {
            try {
                //直接呼叫mService的setWifiEnabled方法
                return mService.setWifiEnabled(enabled);
            } catch (RemoteException e) {
                return false;
            }
        }

2.2、connect方式

        與setWifiEnabled不同,在該方式中,WifiManager利用與WifiServiceImpl之間的AsyncChannel來交換資訊
        @WifiManager.java
        public void connect(int networkId, ActionListener listener) {
            if (networkId < 0) throw new IllegalArgumentException("Network id cannot be negative");
            validateChannel();
            //通過AsyncChannel與WifiServiceImpl傳遞資訊
            sAsyncChannel.sendMessage(CONNECT_NETWORK, networkId, putListener(listener));
        }

2.3、WifiManager小結

        在上面兩節中分別介紹了兩種WifiManager與WifiServiceImpl通訊的方式,其實不僅是以上兩個方法,WifiManager中所有的對外公開的public方法,最終都是通過這兩種方式與WifiServiceImpl進行溝通

        我們可以這樣理解WifiManager:他是WIFI模組向外部應用透漏出來的介面,其他所有應用都可以通過WifiManager操作WIFI各項功能,但是WifiManager本身並不具備處理請求的能力,而是把所有請求轉發給WifiServiceImpl物件,而傳送請求的方式就是直接呼叫或者通過AsyncChannel。

2.4、WifiServiceImpl中對請求的處理

        無論採用何種溝通方式,WifiManager最終都會把應用的請求轉交給WifiServiceImpl來處理。那麼接下來的流程是怎樣的呢?WifiServiceImpl將會如何處理WifiManager轉發過來的請求呢?
        我們繼續跟蹤上面兩個方法的呼叫流程來檢視WifiServiceImpl的處理過程。
        先來看setWifiEnabled()方法,該方法是直接由WifiManager呼叫到WifiServiceImpl中的,其實現如下:
        @WifiServiceImpl.java
        public synchronized boolean setWifiEnabled(boolean enable) {
            //許可權檢查
            enforceChangePermission();


            //許可權檢查
            long ident = Binder.clearCallingIdentity();
            try {
                if (! mSettingsStore.handleWifiToggled(enable)) {
                    return true;
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
            //向WifiController傳送請求
            mWifiController.sendMessage(CMD_WIFI_TOGGLED);
            return true;
        }
        在這裡我們看到,WifiServiceImpl將請求轉交給WifiController來處理。
        下面來看WifiManager中connect()方法的處理,當初WifiManager收到該請求後,通過AsyncChannel的方式向WifiServiceImpl傳送CONNECT_NETWORK的請求,那麼WifiServiceImpl的接下來就需要在自己的Messenger中處理,而這個Messenger是從getWifiServiceMessenger()中傳遞給WifiManager的,我們來看是哪個Messenger來處理該請求:
        @WifiServiceImpl.java
        public Messenger getWifiServiceMessenger() {
            //許可權檢查
            enforceAccessPermission();
            enforceChangePermission();
            //這裡的Messenger的Handler是mClientHandler
            return new Messenger(mClientHandler);
        }
        從這裡看到,WifiManager拿到的Messenger中的Handler其實就是mClientHandler,他是在WifiServiceImpl初始化時被建立的:
        @WifiServiceImpl.java
        public WifiServiceImpl(Context context) {
            ......
            HandlerThread wifiThread = new HandlerThread("WifiService");
            wifiThread.start();
            mClientHandler = new ClientHandler(wifiThread.getLooper());
        }
        也就是說WifiManager通過AsyncChannel傳送的訊息都會在ClientHandler中接收到:
        private class ClientHandler extends Handler {
            ClientHandler(android.os.Looper looper) {
                super(looper);
            }
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case WifiManager.CONNECT_NETWORK:
                    case WifiManager.SAVE_NETWORK: {
                       WifiConfiguration config = (WifiConfiguration) msg.obj;
                       int networkId = msg.arg1;
                       if (msg.what == WifiManager.SAVE_NETWORK) {
                       }
                       if (msg.what == WifiManager.CONNECT_NETWORK) {
                           if (config != null) {
                               //配置config
                               if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
                                   config.creatorUid = Binder.getCallingUid();
                               } else {
                                   config.lastUpdateUid = Binder.getCallingUid();
                               }
                           }
                       }
                       if (config != null && config.isValid()) {
                           //將請求傳送給WifiStateMachine
                           mWifiStateMachine.sendMessage(Message.obtain(msg));
                       } else if (config == null && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
                           mWifiStateMachine.sendMessage(Message.obtain(msg));
                       } else {
                           if (msg.what == WifiManager.CONNECT_NETWORK) {
                               replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED, WifiManager.INVALID_ARGS);
                           } else {
                               replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED, WifiManager.INVALID_ARGS);
                           }
                       }
                       break;
                   }
                }
            }
        }
        從上面這個處理來看,WifiServiceImpl將請求轉交給WifiStateMachine來處理。
        其實WifiServiceImpl對請求的處理與WifiManager類似,他本身並不具備處理事物的能力,只是將請求分類後交由不同的處理者去處理
        以上就是整個WIFI框架的初始化以及內部訊息處理機制,下面用一張圖來標識WIFI內部的訊息流: