Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android4.4(MT8685)源碼WIFI--啟動

Android4.4(MT8685)源碼WIFI--啟動

編輯:關於Android編程

系統啟動時,會在SystemServer中創建一個WifiService的對象,並把這個對象保存在系統服務中

wifi = new WifiService(context);
ServiceManager.addService(Context.WIFI_SERVICE, wifi);

看看WiFiService的構造方法

public WifiService(Context context) {
        mContext = context;

        mInterfaceName =  SystemProperties.get("wifi.interface", "wlan0");

        mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName);
        mWifiStateMachine.enableRssiPolling(true);
        mBatteryStats = BatteryStatsService.getService();
        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);

        mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
        mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName);
        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());
        mWifiController.start();

        mBatchedScanSupported = mContext.getResources().getBoolean(
                R.bool.config_wifi_batched_scan_supported);

        registerForScanModeChange();
        mContext.registerReceiver(
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        ///M: modify for timing issue to access Settings.Global.AIRPLANE_MODE_ON
                        boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
                        SXlog.i(TAG, "ACTION_AIRPLANE_MODE_CHANGED isAirplaneModeOn="+isAirplaneModeOn);
                        
                        if (mSettingsStore.handleAirplaneModeToggled(isAirplaneModeOn)) {

                            mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
                        }
                    }
                },
                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));

        // Adding optimizations of only receiving broadcasts when wifi is enabled
        // can result in race conditions when apps toggle wifi in the background
        // without active user involvement. Always receive broadcasts.
        registerForBroadcasts();

        ///M:
        initializeExtra();
    }

這裡初始化了一個WifiStateMachine和一個WifiController,並且調用了WifiController 的start方法,WifiController 繼承至StateMachine狀態機,這個start方法是父類的方法,表示啟動一個狀態機。我們先來看看WifiController這個狀態機的構造方法

 WifiController(Context context, WifiService service, Looper looper) {
        super(TAG, looper);
        mContext = context;
        mWifiStateMachine = service.mWifiStateMachine;
        mSettingsStore = service.mSettingsStore;
        mLocks = service.mLocks;

        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
        Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null);
        mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);

        ///M: add plugin 
        mWifiFwkExt = MediatekClassFactory.createInstance(IWifiFwkExt.class, mContext);

        addState(mDefaultState);
            addState(mApStaDisabledState, mDefaultState);
            addState(mStaEnabledState, mDefaultState);
                addState(mDeviceActiveState, mStaEnabledState);
                addState(mDeviceInactiveState, mStaEnabledState);
                    addState(mScanOnlyLockHeldState, mDeviceInactiveState);
                    addState(mFullLockHeldState, mDeviceInactiveState);
                    addState(mFullHighPerfLockHeldState, mDeviceInactiveState);
                    addState(mNoLockHeldState, mDeviceInactiveState);
            addState(mStaDisabledWithScanState, mDefaultState);
            addState(mApEnabledState, mDefaultState);
            addState(mEcmState, mDefaultState);
        if (mSettingsStore.isScanAlwaysAvailable()) {
            setInitialState(mStaDisabledWithScanState);
			Log.e("dd","mStaDisabledWithScanState");
        } else {
            setInitialState(mApStaDisabledState);
			Log.e("dd","mApStaDisabledState");
        }
        setLogRecSize(100);
        setLogOnlyTransitions(false);

        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_DEVICE_IDLE);
        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        mContext.registerReceiver(
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        String action = intent.getAction();
                        if (action.equals(ACTION_DEVICE_IDLE)) {
                            sendMessage(CMD_DEVICE_IDLE);
                        } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
                            mNetworkInfo = (NetworkInfo) intent.getParcelableExtra(
                                    WifiManager.EXTRA_NETWORK_INFO);
                        }
                    }
                },
                new IntentFilter(filter));

        initializeAndRegisterForSettingsChange(looper);
    }

這裡參數service就是WifiService,並且通過service得到了WifiService中的WifiStateMachine對象,然後添加了一些狀態對象,設置了初始狀態,調用start方法後,WifiController首先進入mDefaultState狀態,然後進入mApStaDisabledState狀態,此時,WifiController狀態機的狀態為mApStaDisabledState狀態。

讓我們回到WifiService的構造方法中,倒數第二行有個registerForBroadcasts方法

private void registerForBroadcasts() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
        intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
        mContext.registerReceiver(mReceiver, intentFilter);
    }
這個方法注冊了一個廣播,那我們看看接收到注冊的這些action後,會有哪些處理

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            SXlog.d(TAG, "onReceive, action:" + action);
            if (action.equals(Intent.ACTION_SCREEN_ON)) {
                mWifiController.sendMessage(CMD_SCREEN_ON);
            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
                mWifiController.sendMessage(CMD_USER_PRESENT);
            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                mWifiController.sendMessage(CMD_SCREEN_OFF);
            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
                int pluggedType = intent.getIntExtra("plugged", 0);
                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
                        BluetoothAdapter.STATE_DISCONNECTED);
                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
            }
        }
    };
當接收到的廣播為ACTION_SCREEN_ON時,利用mWifiController對象發送一個CMD_SCREEN_ON消息,此時,mWifiController狀態機的狀態為mApStaDisabledState狀態,我們看看這個狀態實現類的processMessage方法

 @Override
        public boolean processMessage(Message msg) {
            SXlog.d(TAG, getName() + msg.toString() + "\n");
            switch (msg.what) {
                case CMD_WIFI_TOGGLED:
                case CMD_AIRPLANE_TOGGLED:
					Log.e("dd","1");
                    ///M: add WifiIpoOff@{
                    boolean wifiIpoOff = (msg.arg1==1) ? true: false;
                    boolean ipoStateChange= false;
                    if(mWifiIpoOff!=wifiIpoOff) ipoStateChange=true;
                    mWifiIpoOff = wifiIpoOff;
                    if(wifiIpoOff ==true){
                        SXlog.d(TAG,"ipooff  don't enable wifi\n");
                        break;
                    }
                    if (mSettingsStore.isWifiToggleEnabled()) {
                    //@}
                        if (doDeferEnable(msg)) {
                            if (mHaveDeferredEnable) {
                                //  have 2 toggles now, inc serial number an ignore both
                                mDeferredEnableSerialNumber++;
                            }
                            mHaveDeferredEnable = !mHaveDeferredEnable;
                            break;
                        }
                        if (mDeviceIdle == false) {
							Log.e("dd","4");
                            transitionTo(mDeviceActiveState);
                        } else {
                            checkLocksAndTransitionWhenDeviceIdle();
                        }
                    ///M: check scan always avaliable only when ipo change from ipo on to off
                    }else if (ipoStateChange ==true && mSettingsStore.isScanAlwaysAvailable() && mSettingsStore.isAirplaneModeOn()==false ) {
                        SXlog.d(TAG,"ipoStateChange = "+ipoStateChange + "isAirplaneModeOn= "+mSettingsStore.isAirplaneModeOn());
                        transitionTo(mStaDisabledWithScanState);
                    }
                    break;
                case CMD_SCAN_ALWAYS_MODE_CHANGED:
                    if (mSettingsStore.isScanAlwaysAvailable()) {
                        transitionTo(mStaDisabledWithScanState);
                    }
                    break;
                case CMD_SET_AP:
                    if (msg.arg1 == 1) {
                        mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
                                true);
                        transitionTo(mApEnabledState);
                    }
                    break;
                case CMD_DEFERRED_TOGGLE:
                    if (msg.arg1 != mDeferredEnableSerialNumber) {
                        log("DEFERRED_TOGGLE ignored due to serial mismatch");
                        break;
                    }
                    log("DEFERRED_TOGGLE handled");
                    sendMessage((Message)(msg.obj));
                    break;
                default:
                    return NOT_HANDLED;
            }
            return HANDLED;
        }

注意,這裡沒有處理CMD_SCREEN_ON消息,根據狀態機的機制,子狀態沒處理的消息,將由父狀態處理,mApStaDisabledState的父狀態為mDefaultState狀態,看看它的processMessage方法

@Override
        public boolean processMessage(Message msg) {
            SXlog.d(TAG, getName() + msg.toString() + "\n");
            switch (msg.what) {
                case CMD_SCREEN_ON:
                    mAlarmManager.cancel(mIdleIntent);
                    mScreenOff = false;
                    mDeviceIdle = false;
					Log.e("dd","mDeviceIdle = false;");
                    ///M: @{
                    mWifiStateMachine.setDeviceIdle(mDeviceIdle);
                    ///@}
                    updateBatteryWorkSource();
                    break;
                case CMD_SCREEN_OFF:
                    mScreenOff = true;
                    /*
                    * Set a timer to put Wi-Fi to sleep, but only if the screen is off
                    * AND the "stay on while plugged in" setting doesn't match the
                    * current power conditions (i.e, not plugged in, plugged in to USB,
                    * or plugged in to AC).
                    */
                    if (!shouldWifiStayAwake(mPluggedType)) {
                        //Delayed shutdown if wifi is connected
                        if (mNetworkInfo.getDetailedState() ==
                                NetworkInfo.DetailedState.CONNECTED) {
                            if (DBG) Slog.d(TAG, "set idle timer: " + mIdleMillis + " ms");
                            ///M: modify to use Exact alarm for accuracy
                            mAlarmManager.setExact(AlarmManager.RTC_WAKEUP,
                                    System.currentTimeMillis() + mIdleMillis, mIdleIntent);
                        } else {
                            sendMessage(CMD_DEVICE_IDLE);
                        }
                    }
                    break;
                case CMD_DEVICE_IDLE:
                    mDeviceIdle = true;
                    ///M: @{
                    mWifiStateMachine.setDeviceIdle(mDeviceIdle);
                    ///@}
                    
                    updateBatteryWorkSource();
                    break;
                case CMD_BATTERY_CHANGED:
                    /*
                    * Set a timer to put Wi-Fi to sleep, but only if the screen is off
                    * AND we are transitioning from a state in which the device was supposed
                    * to stay awake to a state in which it is not supposed to stay awake.
                    * If "stay awake" state is not changing, we do nothing, to avoid resetting
                    * the already-set timer.
                    */
                    int pluggedType = msg.arg1;
                    if (DBG) Slog.d(TAG, "battery changed pluggedType: " + pluggedType);
                    if (mScreenOff && shouldWifiStayAwake(mPluggedType) &&
                            !shouldWifiStayAwake(pluggedType)) {
                        long triggerTime = System.currentTimeMillis() + mIdleMillis;
                        if (DBG) Slog.d(TAG, "set idle timer for " + mIdleMillis + "ms");
                        mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
                    }

                    mPluggedType = pluggedType;
                    break;
                case CMD_SET_AP:
                case CMD_SCAN_ALWAYS_MODE_CHANGED:
                case CMD_LOCKS_CHANGED:
                case CMD_WIFI_TOGGLED:
                case CMD_AIRPLANE_TOGGLED:
                case CMD_EMERGENCY_MODE_CHANGED:
                    break;
                case CMD_USER_PRESENT:
                    mFirstUserSignOnSeen = true;
                    break;
                case CMD_DEFERRED_TOGGLE:
                    log("DEFERRED_TOGGLE ignored due to state change");
                    break;
                default:
                    throw new RuntimeException("WifiController.handleMessage " + msg.what);
            }
            return HANDLED;
        }

    }

果然,這裡有處理CMD_SCREEN_ON消息,這裡要注意的是

mDeviceIdle = false;
稍後我們會用到這個flag,再一次回到WifiService的構造方法,其中有這麼一段代碼

mContext.registerReceiver(
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        ///M: modify for timing issue to access Settings.Global.AIRPLANE_MODE_ON
                        boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
                        SXlog.i(TAG, "ACTION_AIRPLANE_MODE_CHANGED isAirplaneModeOn="+isAirplaneModeOn);
                        
                        if (mSettingsStore.handleAirplaneModeToggled(isAirplaneModeOn)) {

                            mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
                        }
                    }
                },
                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));

這裡注冊了一個捕捉ACTION_AIRPLANE_MODE_CHANGED的廣播,接收到這個廣播後,通過mWifiController發送一個CMD_AIRPLANE_TOGGLED的消息,來看看接收到這個消息的地方,還是在WifiController的當前狀態mApStaDisabledState實現類的 processMessage方法中

 @Override
        public boolean processMessage(Message msg) {
            SXlog.d(TAG, getName() + msg.toString() + "\n");
            switch (msg.what) {
                case CMD_WIFI_TOGGLED:
                case CMD_AIRPLANE_TOGGLED:
					Log.e("dd","1");
                    ///M: add WifiIpoOff@{
                    boolean wifiIpoOff = (msg.arg1==1) ? true: false;
                    boolean ipoStateChange= false;
                    if(mWifiIpoOff!=wifiIpoOff) ipoStateChange=true;
                    mWifiIpoOff = wifiIpoOff;
                    if(wifiIpoOff ==true){
                        SXlog.d(TAG,"ipooff  don't enable wifi\n");
                        break;
                    }
                    if (mSettingsStore.isWifiToggleEnabled()) {
                    //@}
                        if (doDeferEnable(msg)) {
                            if (mHaveDeferredEnable) {
                                //  have 2 toggles now, inc serial number an ignore both
                                mDeferredEnableSerialNumber++;
                            }
                            mHaveDeferredEnable = !mHaveDeferredEnable;
                            break;
                        }
                        if (mDeviceIdle == false) {
							Log.e("dd","4");
                            transitionTo(mDeviceActiveState);
                        } else {
                            checkLocksAndTransitionWhenDeviceIdle();
                        }
                    ///M: check scan always avaliable only when ipo change from ipo on to off
                    }else if (ipoStateChange ==true && mSettingsStore.isScanAlwaysAvailable() && mSettingsStore.isAirplaneModeOn()==false ) {
                        SXlog.d(TAG,"ipoStateChange = "+ipoStateChange + "isAirplaneModeOn= "+mSettingsStore.isAirplaneModeOn());
                        transitionTo(mStaDisabledWithScanState);
                    }
                    break;
                case CMD_SCAN_ALWAYS_MODE_CHANGED:
                    if (mSettingsStore.isScanAlwaysAvailable()) {
                        transitionTo(mStaDisabledWithScanState);
                    }
                    break;
                case CMD_SET_AP:
                    if (msg.arg1 == 1) {
                        mWifiStateMachine.setHostApRunning((WifiConfiguration) msg.obj,
                                true);
                        transitionTo(mApEnabledState);
                    }
                    break;
                case CMD_DEFERRED_TOGGLE:
                    if (msg.arg1 != mDeferredEnableSerialNumber) {
                        log("DEFERRED_TOGGLE ignored due to serial mismatch");
                        break;
                    }
                    log("DEFERRED_TOGGLE handled");
                    sendMessage((Message)(msg.obj));
                    break;
                default:
                    return NOT_HANDLED;
            }
            return HANDLED;
        }

當系統Wifi為開時,並且mDeviceIdle為false時,會把當前狀態轉換為mDeviceActiveState狀態,mDeviceActiveState的父狀態為mStaEnabledState狀態,所以會先進入mStaEnabledState然後進入mDeviceActiveState狀態,我們看看mStaEnabledState狀態的實現類的enter方法

@Override
        public void enter() {
        	Log.e("dd","StaEnabledState");
            if (DBG) log(getName() + "\n");        
            mWifiStateMachine.setSupplicantRunning(true);
        }

這裡調用了WifiService中的WifiStateMachine對象的setSupplicantRunning方法

 public void setSupplicantRunning(boolean enable) {
        if (enable) {
            sendMessage(CMD_START_SUPPLICANT);
        } else {
            sendMessage(CMD_STOP_SUPPLICANT);
        }
    }

當參數為true時,發送一個CMD_START_SUPPLICANT消息,那麼WifiStateMachine當前的狀態是什麼呢?看看它的構造方法吧,其中添加狀態和初始狀態的代碼為

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(mCaptivePortalCheckState, mL2ConnectedState);
                            addState(mConnectedState, 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);

初始狀態為mInitialState,看看它的實現類的processMessage方法

 @Override
        public boolean processMessage(Message message) {
            if (DBG) log(getName() + message.toString() + "\n");
            switch (message.what) {
                case CMD_START_SUPPLICANT:
                    setWifiState(WIFI_STATE_ENABLING);
                    if (mWifiNative.loadDriver()) {
                        try {
                            mNwService.wifiFirmwareReload(mInterfaceName, "STA");
                        } catch (Exception e) {
                            loge("Failed to reload STA firmware " + e);
                            // continue
                        }

                        try {
                            // A runtime crash can leave the interface up and
                            // this affects connectivity when supplicant starts up.
                            // Ensure interface is down before a supplicant start.
                            mNwService.setInterfaceDown(mInterfaceName);
                            // Set privacy extensions
                            mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);

                           // IPv6 is enabled only as long as access point is connected since:
                           // - IPv6 addresses and routes stick around after disconnection
                           // - kernel is unaware when connected and fails to start IPv6 negotiation
                           // - kernel can start autoconfiguration when 802.1x is not complete
                            mNwService.disableIpv6(mInterfaceName);
                        } catch (RemoteException re) {
                            loge("Unable to change interface settings: " + re);
                        } catch (IllegalStateException ie) {
                            loge("Unable to change interface settings: " + ie);
                        }

                       /* Stop a running supplicant after a runtime restart
                        * Avoids issues with drivers that do not handle interface down
                        * on a running supplicant properly.
                        */
                        mWifiMonitor.killSupplicant(mP2pSupported);
                        if(mWifiNative.startSupplicant(mP2pSupported)) {
                            if (DBG) log("Supplicant start successful");
                            mWifiMonitor.startMonitoring();
                            transitionTo(mSupplicantStartingState);
                        } else {
                            loge("Failed to start supplicant!");
                        }
                    } else {
                        loge("Failed to load driver");
                    }
                    break;
                case CMD_START_AP:
                    if (mWifiNative.loadDriver()) {
                        setWifiApState(WIFI_AP_STATE_ENABLING);
                        transitionTo(mSoftApStartingState);
                    } else {
                        loge("Failed to load driver for softap");
                    }
                ///M: for Hotknot, enable wifi for p2p, sta mode should not connect@{
                case WifiManager.SET_WIFI_DISCONNECT:
                    if(message.arg1 == 1){
                        mHotknotConnected.set(true);
                    }else{
                        mHotknotConnected.set(false);
                    }
                    sendMessage(M_CMD_UPDATE_BGSCAN);
                    break;
                    ///@}
                default:
                    return NOT_HANDLED;
            }
            return HANDLED;
        }

接收到CMD_START_SUPPLICANT消息後,首先會調用mWifiNative的loadDriver方法,loadDriver是一個本地方法,其作用是加載相應的Wifi驅動,如果驅動加載成功,會調用mWifiMonitor的startMonitoring方法,並且把當前的 狀態轉為mSupplicantStartingState狀態。我們來看看mWifiMonitor這個對象,mWifiMonitor是一個WifiMonitor對象,它負責從wpa_supplicant接收消息,運行在一個獨立的線程中。看看構造方法

public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) {
        if (DBG) Log.d(TAG, "Creating WifiMonitor");
        mWifiNative = wifiNative;
        mInterfaceName = wifiNative.mInterfaceName;
        mWifiStateMachine = wifiStateMachine;
        mMonitoring = false;

        WifiMonitorSingleton.getMonitor().registerInterfaceMonitor(mInterfaceName, this);
    }

這裡傳入了StateMachine對象和WifiNative對象,接著我們看看startMonitoring方法

public void startMonitoring() {
        WifiMonitorSingleton.getMonitor().startMonitoring(mInterfaceName);
    }
這裡調用WifiMonitor內部類WifiMonitorSingleton的startMonitoring方法

 public synchronized void startMonitoring(String iface) {
            WifiMonitor m = mIfaceMap.get(iface);
            if (m == null) {
                Log.e(TAG, "startMonitor called with unknown iface=" + iface);
                return;
            }

            Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected);

            if (mConnected) {
                m.mMonitoring = true;
                m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
            } else {
                if (DBG) Log.d(TAG, "connecting to supplicant");
                int connectTries = 0;
                while (true) {
                    if (mWifiNative.connectToSupplicant()) {
                        m.mMonitoring = true;
                        m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
                        new MonitorThread(mWifiNative, this).start();
                        mConnected = true;
                        break;
                    }
                    if (connectTries++ < 5) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException ignore) {
                        }
                    } else {
                    Log.d(TAG, "rmIfaceMap remove " + iface);
                        mIfaceMap.remove(iface);
                        ///M:@{
                        if (!m.mInterfaceName.equals("ap0")) {
                            m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
                        }
                        ///@}
                        Log.e(TAG, "startMonitoring(" + iface + ") failed! " );
                        break;
                    }
                }
            }
        }

這裡會啟動一個MonitorThread線程,看看這個線程的構造方法

public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) {
            super("WifiMonitor");
            mWifiNative = wifiNative;
            mWifiMonitorSingleton = wifiMonitorSingleton;
        }

沒做什麼,再看run方法

 public void run() {
            //noinspection InfiniteLoopStatement
            for (;;) {
                String eventStr = mWifiNative.waitForEvent();

                // Skip logging the common but mostly uninteresting scan-results event
                if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
                    Log.d(TAG, "Event [" + eventStr + "]");
                }

                String iface = "p2p0";
                WifiMonitor m = null;
                mStateMachine = null;

                if (eventStr.startsWith("IFNAME=")) {
                    int space = eventStr.indexOf(' ');
                    if (space != -1) {
                        iface = eventStr.substring(7,space);
                        Log.d(TAG, "iface " + iface);
                        m = mWifiMonitorSingleton.getMonitor(iface);
                        if(m==null)Log.d(TAG, "hcan get mm  " + iface);
                        if (m == null && iface.startsWith("p2p-")) {
                            // p2p interfaces are created dynamically, but we have
                            // only one P2p state machine monitoring all of them; look
                            // for it explicitly, and send messages there ..
                            m = mWifiMonitorSingleton.getMonitor("p2p0");
                        }
                        eventStr = eventStr.substring(space + 1);
                    }
                } else {
                    ///M: if ap0 exist, it could be hotspot event
                    
                    m = mWifiMonitorSingleton.getMonitor("ap0");
                    if(m!=null){
                        if(m.mMonitoring){
                            //we find hotspot active
                        }else{
                            //try p2p0
                            m = mWifiMonitorSingleton.getMonitor("p2p0");
                        }
                     }else{                    
                        // events without prefix belong to p2p0 monitor
                        m = mWifiMonitorSingleton.getMonitor("p2p0");
                     }                    
                }

                if (m != null) {
                    if (m.mMonitoring) {
                        mStateMachine = m.mWifiStateMachine;
                    } else {
                        if (DBG) Log.d(TAG, "Dropping event because monitor (" + iface +
                                            ") is stopped");
                        continue;
                    }
                }

                if (mStateMachine != null) {
                    if (dispatchEvent(eventStr, m.mInterfaceName)) {
                        //M: when dispatchEvent=true means break from waitForEvent
                        //M: for hotspot clear hotspot data
                        if(m.mInterfaceName.equals("ap0")){
                            m.mMonitoring =false;
                            mWifiNative.closeSupplicantConnection();
                            Log.d(TAG, "ap0 get TEMINATING 1");
                        }
                        break;
                    }
                } else {
                    if (DBG) Log.d(TAG, "Sending to all monitors because there's no interface id");
                    boolean done = false;
                    Iterator> it =
                            mWifiMonitorSingleton.mIfaceMap.entrySet().iterator();
                    while (it.hasNext()) {
                        Map.Entry e = it.next();
                        m = e.getValue();
                        mStateMachine = m.mWifiStateMachine;
                        if (dispatchEvent(eventStr,null)) {
                            done = true;
                        }
                    }

                    if (done) {
                        
                        //M: for hotspot clear hotspot data
                        if(m.mInterfaceName.equals("ap0")){
                            m.mMonitoring =false;
                            mWifiNative.closeSupplicantConnection();
                            Log.d(TAG, "ap0 get TEMINATING 2");
                        }

                        // After this thread terminates, we'll no longer
                        // be connected to the supplicant
                        if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events");
                        mWifiMonitorSingleton.mConnected = false;
                        break;
                    }
                }
            }
        }

這裡調用了mWifiNative的waitForEvent方法,這個方法通過jni調用本地方法讀取wpa_supplicant的消息,接著轉發出去
while (it.hasNext()) {
                        Map.Entry e = it.next();
                        m = e.getValue();
                        mStateMachine = m.mWifiStateMachine;
                        if (dispatchEvent(eventStr,null)) {
                            done = true;
                        }
                    }


看看dispatchEvent方法

 /* @return true if the event was supplicant disconnection */
        private boolean dispatchEvent(String eventStr, String iface) {

            if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
                if ((eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
                        0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR))
                        ///M:@{
                        || (eventStr.startsWith(AUTHENTICATION_TIMEOUT_PREFIX_STR)
                            && 0 < eventStr.indexOf(AUTHENTICATION_TIMEOUT_STR))) {
                        ///@}
                    mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
                } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
                    mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
                } else if (eventStr.startsWith(WPS_FAIL_STR)) {
                    handleWpsFailEvent(eventStr);
                } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
                    mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
                } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
                    mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
                } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
                    handleP2pEvents(eventStr);
                } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
                    handleHostApEvents(eventStr, iface);
                ///M:@{
                } else if (eventStr.startsWith(EAP_FAST_NEW_PAC_UPDATED)) {
                    mStateMachine.sendMessage(NEW_PAC_UPDATED_EVENT);
                ///M: whole chip reset fail
                } else if (eventStr.startsWith(WHOLE_CHIP_RESET_FAIL_STRING)){
                    mStateMachine.sendMessage(WHOLE_CHIP_RESET_FAIL_EVENT);
                /** M: NFC Float II @{ */
                } else if (eventStr.startsWith(WPS_ER_ENROLLEE_ADD_STR)) {
                    mStateMachine.sendMessage(WPS_ER_ENROLLEE_ADD_EVENT, eventStr);
                } else if (eventStr.startsWith(WPS_ER_AP_ADD_STR)) {
                    mStateMachine.sendMessage(WPS_ER_AP_ADD_EVENT, eventStr);
                /** } */
                }
                ///@}
                else {
                    if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);
                }
                return false;
            }

            String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
            int nameEnd = eventName.indexOf(' ');
            if (nameEnd != -1)
                eventName = eventName.substring(0, nameEnd);
            if (eventName.length() == 0) {
                if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name");
                return false;
            }
            /*
             * Map event name into event enum
             */
            int event;
            if (eventName.equals(CONNECTED_STR))
                event = CONNECTED;
            else if (eventName.equals(DISCONNECTED_STR)) {
                event = DISCONNECTED;
                ///M: add
                handleP2pEvents(eventStr);
            } else if (eventName.equals(STATE_CHANGE_STR))
                event = STATE_CHANGE;
            else if (eventName.equals(SCAN_RESULTS_STR))
                event = SCAN_RESULTS;
            else if (eventName.equals(LINK_SPEED_STR))
                event = LINK_SPEED;
            else if (eventName.equals(TERMINATING_STR))
                event = TERMINATING;
            else if (eventName.equals(DRIVER_STATE_STR))
                event = DRIVER_STATE;
            else if (eventName.equals(EAP_FAILURE_STR))
                event = EAP_FAILURE;
            else if (eventName.equals(ASSOC_REJECT_STR))
                event = ASSOC_REJECT;
            ///M: @{                        
            else if (eventName.equals(WAPI_NO_CERTIFICATION_STRING))
                event = NO_CERTIFICATION;
            ///@}
            else
                event = UNKNOWN;

            String eventData = eventStr;
            if (event == DRIVER_STATE || event == LINK_SPEED)
                eventData = eventData.split(" ")[1];
            else if (event == STATE_CHANGE || event == EAP_FAILURE) {
                int ind = eventStr.indexOf(" ");
                if (ind != -1) {
                    eventData = eventStr.substring(ind + 1);
                }
            } else {
                int ind = eventStr.indexOf(" - ");
                if (ind != -1) {
                    eventData = eventStr.substring(ind + 3);
                }
            }

            if (event == STATE_CHANGE) {
                handleSupplicantStateChange(eventData);
            } else if (event == DRIVER_STATE) {
                handleDriverEvent(eventData);
            } else if (event == TERMINATING) {
                Log.d(TAG, "event == TERMINATING " );
                /**
                 * Close the supplicant connection if we see
                 * too many recv errors
                 */
                if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
                    if (++mRecvErrors > MAX_RECV_ERRORS) {
                        if (DBG) {
                            Log.d(TAG, "too many recv errors, closing connection");
                        }
                    } else {
                        return false;
                    }
                }

                // notify and exit
                if(iface!=null && !iface.equals("ap0")){
                    mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
                }
                Log.d(TAG, "Exit because of receiving terminating for " + getName() + ", id:" + getId());
                return true;
            } else if (event == EAP_FAILURE) {
                if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
                    mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
                }
            } else if (event == ASSOC_REJECT) {
                mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT);
            } else {
                handleEvent(event, eventData);
            }
            mRecvErrors = 0;
            return false;
        }

經過一系列處理調用handleEvent方法

 void handleEvent(int event, String remainder) {
            switch (event) {
                case DISCONNECTED:
                    handleNetworkStateChange(NetworkInfo.DetailedState.DISCONNECTED, remainder);
                    break;

                case CONNECTED:
                    handleNetworkStateChange(NetworkInfo.DetailedState.CONNECTED, remainder);
                    break;

                case SCAN_RESULTS:
                    mStateMachine.sendMessage(SCAN_RESULTS_EVENT);
                    break;
                ///M: @{
                case NO_CERTIFICATION:
                    mStateMachine.sendMessage(WAPI_NO_CERTIFICATION_EVENT);
                    break;
                ///@}
                case UNKNOWN:
                    break;
            }
        }

以SCAN_RESULTS_EVENT為例,狀態機發送一個SCAN_RESULTS_EVENT消息,這個狀態機是WifiStateMachine對象,WifiStateMachine當前的狀態為SupplicantStartedState(中間的過程暫時忽略),看看processMessage方法相關代碼

case WifiMonitor.SCAN_RESULTS_EVENT:
                    setScanResults();
                    if (mWifiFwkExt.hasCustomizedAutoConnect()) {
                        mShowReselectDialog = false;
                        Xlog.d(TAG, "SCAN_RESULTS_EVENT, mScanForWeakSignal:" + mScanForWeakSignal);
                        if (mScanForWeakSignal) {
                            showReselectionDialog();
                        }
                        mDisconnectNetworkId = INVALID_NETWORK_ID;
                    }

                    sendScanResultsAvailableBroadcast();
                    mScanResultIsPending = false;
                    break;

這裡會調用sendScanResultsAvailableBroadcast發送廣播,把掃描到的Wifi熱點信息發送給廣播接收者

private void sendScanResultsAvailableBroadcast() {
        noteScanEnd();
        Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
        intent.putExtra(IWifiFwkExt.EXTRA_SHOW_RESELECT_DIALOG_FLAG, mShowReselectDialog);
        mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
    }

至此,Wifi啟動的一個大概流程就先分析到這裡!










  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved