天天看點

Android 網絡管家ConnectivityManager

Android提供了多種網絡連結通道,最常見的是WIFI和移動基站通信(Cellular),另外還可将終端本身作為熱點(Wifi Access Point),也可通過WIFI進行将兩個終端直接進行連接配接(Wifi P2P),進而互動資料;同時還支援藍牙将WIFI作為資料熱點(Access Point),為其他裝置提供網絡接入。

對于移動通信,不同的營運商提供了不同的服務,網絡提供的服務能力也各不相同。那麼,Android是如何區分網絡的承載能力的?為了區分不同網絡的承載能力,Android提供了多達20種網絡能力用以區分網絡資料的接入方式(以下隻列舉常見的類型):

  • NET_CAPABILITY_MMS: Multimedia Messaging Service,表示網絡可以通過MMSC發送MMS(彩信);
  • NET_CAPABILITY_SUPL: Secure User Plane Location,網絡可以使用基站進行輔助GPS定位;
  • NET_CAPABILITY_DUN : Dial-Up Network,網絡支援撥号的方式接入
  • NET_CAPABILITY_FOTA : Firmware Over The Air,網絡可以使用FOTA伺服器進行軟體更新;
  • NET_CAPABILITY_IMS : IP Multimedia Subsystem, 網絡可以使用多媒體系統服務
  • NET_CAPABILITY_CBS : Cell BroadCast Messaging, 網絡可以接收基站廣播消息
  • NET_CAPABILITY_WIFI_P2P:Wifi Peer to Peer(Wifi Direct),網絡支援WIFI直連
  • NET_CAPABILITY_INTERNET:網絡支援網際網路通路

Android中有一個系統服務

ConnectivityService

用于管理網絡連接配接的狀态與資訊,通過該系統服務,我們可以查詢目前可用的網絡資訊,發起網絡連結請求,設定網絡屬性與參數等。在這篇文章裡,将從以下幾個方面來講解下

ConnectivityService

具體是如何工作的?

  • ConnectivityManager

    如何使用;
  • ConnectivityService

    的初始化;
  • ConnectivityService

    是如何與Telephony資料子產品進行互動的
以下分析均基于Android MM6.0

ConnectivityManager常用接口

ConnectivityManager提供了很多接口用于擷取系統目前的網絡連接配接資訊:

  • getAllNetworkInfo()

    : 傳回所有網絡資訊
  • getActiveNetworkInfo()

    :擷取目前激活的網絡連接配接資訊
  • getNetworkForType

    : 擷取指定類型的網絡
  • requestNetwork(...)

    : 請求建立某種類型的網絡
  • setAirplaneMode()

    : 開啟飛行模式
  • addDefaultNetworkActiveListener()

    : 監聽預設網絡連接配接是否激活
  • registerNetworkCallback()

    : 監聽某個網絡請求的狀态,可用時進行回調

比如,現在監聽移動資料的狀态,首先需要在

AndroidManifest.xml

中聲明網絡相關的權限:

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
           
  • 擷取目前激活網絡的資訊
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);

    NetworkInfo network = cm.getActiveNetworkInfo();
    int type = ConnectivityManager.TYPE_DUMMY;
    if(network != null) {
        type = network.getType();
    }

    if (type == ConnectivityManager.TYPE_MOBILE) {
        Log.v(TAG, " mobile data is connected: " + network.isConnected());
    } else if (type == ConnectivityManager.TYPE_WIFI){
        Log.v(TAG, "wifi is connected: " + network.isConnected());
    }
           
  • 監聽網絡可用(WIFI或者移動資料)的變化
ConnectivityManager cm = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
    NetworkRequest.Builder builder = new NetworkRequest.Builder();
    NetworkRequest request = builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
                        .build();

    cm.requestNetwork(request, new ConnectivityManager.NetworkCallback() {

        @Override
        public void onAvailable(Network network) {
            Log.v(TAG, "onAvailable(): network " + network);
           // do something
        }

    });

           

ConnectivityService

初始化

在系統程序

SystemServer

啟動過程中,會建立一個

ConnectivityService

一個執行個體:

try {
        connectivity = new ConnectivityService(
                context, networkManagement, networkStats, networkPolicy);
        // 将ConnectivityService添加注冊到系統
        ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
        networkStats.bindConnectivityManager(connectivity);
        networkPolicy.bindConnectivityManager(connectivity);
    } catch (Throwable e) {
        reportWtf("starting Connectivity Service", e);
    }
           

ConnectivityService初始化時主要做了以下幾個事情:

  • 建立預設的移動資料請求;
  • 初始化消息隊列;
  • 網絡熱點狀态監聽
protected ConnectivityService(Context context, INetworkManagementService netManager,
            INetworkStatsService statsService, INetworkPolicyManager policyManager,
            IpConnectivityLog logger) {
        // 建立預設的網絡請求
        mDefaultRequest = createInternetRequestForTransport(-, NetworkRequest.Type.REQUEST);
        NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
        mNetworkRequests.put(mDefaultRequest, defaultNRI);
        // 建立預設的移動資料網絡請求
        mDefaultMobileDataRequest = createInternetRequestForTransport(
                NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
        // 建立消息處理線程
        mHandlerThread = createHandlerThread();
        mHandlerThread.start();
        mHandler = new InternalHandler(mHandlerThread.getLooper());
        mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
        ....
        //讀取網絡屬性
        String[] naStrings = context.getResources().getStringArray(
                com.android.internal.R.array.networkAttribute);
        for (String naString : naStrings) {
            try {
                NetworkConfig n = new NetworkConfig(naString);
                ....
                mNetConfigs[n.type] = n;
                mNetworksDefined++;
            } catch(Exception e) {
                // ignore it - leave the entry null
            }
        }
        // 網絡資料熱點控制
        mTethering = new Tethering(mContext, mNetd, statsService, mPolicyManager);
        ....

        try {
            //通過NETD監控資料流量上下行方向
            mNetd.registerObserver(mTethering);
            mNetd.registerObserver(mDataActivityObserver);
        } catch (RemoteException e) {
            loge("Error registering observer :" + e);
        }

        mSettingsObserver = new SettingsObserver(mContext, mHandler);
        registerSettingsCallbacks();

        mDataConnectionStats = new DataConnectionStats(mContext);
        mDataConnectionStats.startMonitoring();

        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);

        mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager,
                mContext.getSystemService(NotificationManager.class));
        // 網絡資料使用控制
        final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
                LingerMonitor.DEFAULT_NOTIFICATION_DAILY_LIMIT);
        final long rateLimit = Settings.Global.getLong(mContext.getContentResolver(),
                Settings.Global.NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS,
                LingerMonitor.DEFAULT_NOTIFICATION_RATE_LIMIT_MILLIS);
        mLingerMonitor = new LingerMonitor(mContext, mNotifier, dailyLimit, rateLimit);
    }


           

AMS(ActiviyManagerService)初始化完成後,系統啟動完成,

SystemServer

會調用各個Service的SystemReady函數,

ConnectivityService

開始執行:

void systemReady() {    
        // 配置全局代理
        loadGlobalProxy();
        // load the global proxy at startup
        mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));

        // Configure whether mobile data is always on.
        mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON));

        mHandler.sendMessage(mHandler.obtainMessage(EVENT_SYSTEM_READY));
        // 網絡權限監控
        mPermissionMonitor.startMonitoring();
    }
           

ConnectivityService如何與Telephony進行互動

ConnectivityService如何與Telephony互動了?當手機通過基站連接配接上資料網絡時,Telephony是如何告知

ConnectivityService

網絡資訊的?同時,使用者在發送彩信時需要進行資料的配置;在進行視訊通話時需要請求IMS服務;FOTA更新時需要通路FOTA伺服器,這幾種情況下ConnectivityService會向Telephony發送配置網絡的請求,以特定的方式通路網絡。在分析Telephony與ConnetivityService具體的互動過程之前,首先來看一看Telephony是如何管理資料連接配接的?

Telephony資料連結管理

Telephony與資料連接配接相關的主要代碼有如下幾個類:

  • ApnContext/ApnSetting

    : APN(Access Point Name,控制資料以何種方式接入網絡)設定相關,Telephony初始化時,會加載資源檔案

    config.xml

    中的

    networkAttributes

    配置檔案,這裡每個網絡類型都對應一個

    ApnContenxt

    執行個體;
<string-array translatable="false" name="networkAttributes">
            <item>"wifi,1,1,1,-1,true"</item>
            <item>"mobile,0,0,0,-1,true"</item>
            <item>"mobile_mms,2,0,2,60000,true"</item>
            <item>"mobile_supl,3,0,2,60000,true"</item>
            <item>"mobile_hipri,5,0,3,60000,true"</item>
            <item>"mobile_fota,10,0,2,60000,true"</item>
            <item>"mobile_ims,11,0,2,60000,true"</item>
            <item>"mobile_cbs,12,0,2,60000,true"</item>
            <item>"wifi_p2p,13,1,0,-1,true"</item>
            <item>"mobile_ia,14,0,2,-1,true"</item>
            <item>"mobile_emergency,15,0,2,-1,true"</item>
        </string-array>

           
  • DataConnection

    : 表示單個資料連接配接,是一個狀态向量機,有Activating,Active,Disconnecting,Inactive以及Retring等幾種狀态。

    DataConnection

    中有一個私有類

    DcNetworkAgent

    (繼承自

    NetworkAgent

    ),用于向

    ConnectivityService

    發送目前網絡連接配接的狀态資訊,

    ConnectivityService

    接受到網絡狀态之後,就會更新網絡。
private class DcNetworkAgent extends NetworkAgent {
        public DcNetworkAgent(Looper l, Context c, String TAG, NetworkInfo ni,
                NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
            super(l, c, TAG, ni, nc, lp, score, misc);
        }

        @Override
        protected void unwanted() {
            if (mNetworkAgent != this) {
                log("DcNetworkAgent: unwanted found mNetworkAgent=" + mNetworkAgent +
                        ", which isn't me.  Aborting unwanted");
                return;
            }
            // this can only happen if our exit has been called - we're already disconnected
            if (mApnContexts == null) return;

            for (ConnectionParams cp : mApnContexts.values()) {
                final ApnContext apnContext = cp.mApnContext;
                final Pair<ApnContext, Integer> pair =
                        new Pair<ApnContext, Integer>(apnContext, cp.mConnectionGeneration);
                log("DcNetworkAgent: [unwanted]: disconnect apnContext=" + apnContext);
                Message msg = mDct.obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair);
                DisconnectParams dp = new DisconnectParams(apnContext, apnContext.getReason(), msg);
                DataConnection.this.sendMessage(DataConnection.this.
                        obtainMessage(EVENT_DISCONNECT, dp));
            }
        }
        ....
    }

           

NetworkAgent

是一個代理者的角色,負責網絡承載對象(如WIFI/WIFI直連,移動資料,藍牙熱點)與

ConnectivityService

之間的互動
  • DcController

    : 資料連接配接控制,用以管理目前所有的資料連接配接;
  • DcAsyncChannel

    : 資料連接配接的異步通道,每個資料連接配接都對應這樣一個異步通道,用戶端想要建立或取消一個資料連接配接都應該通過對應的異步通道來發送請求指令;
  • DcTracker/DcTrackerBase

    : 維護系統的APN,管理網絡連接配接狀态;
  • DctController

    : 資料連接配接的核心類,控制網絡狀态的切換,負責與ConnectivityService互動,處理其發送過來的網絡請求。
代碼路徑:
  • /android/frameworks/opt/telephony/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
  • /android/frameworks/base/core/java/android/net/NetworkAgent.java

Telephony與ConnectivityService互動過程

剛才提到,當移動終端連接配接上移動網絡之後,Telephony會通過

NetworkAgent

将網絡資訊發送給

ConnectivityService

,讓其更新目前的網絡資訊;另一方面,當使用者在發送彩信或者撥打視訊通話時,

ConnectivityService

會主動向Telephony發送網絡配置的請求。那麼,這兩個過程是如何進行的了?

Telephony告知ConnectivityService網絡資訊

在資料連接配接建立完成之後,Telephony通過

DcNetworkAgent

ConnectivityService

發送消息,告知其網絡資訊。初始化時,

DataConnection

的預設狀态是Inactive:

private DataConnection(PhoneBase phone, String name, int id,
                    DcTrackerBase dct, DcTesterFailBringUpAll failBringUpAll,
                    DcController dcc) {
            super(name, dcc.getHandler());
            ....
            mDataRegState = mPhone.getServiceState().getDataRegState();
            int networkType = ss.getDataNetworkType();
            mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_MOBILE,
                    networkType, NETWORK_TYPE, TelephonyManager.getNetworkTypeName(networkType));
            mNetworkInfo.setRoaming(ss.getDataRoaming());
            mNetworkInfo.setIsAvailable(true);

            addState(mDefaultState);
            ....
            // 初始化狀态
            setInitialState(mInactiveState);
    }

           

狀态機接收到建立資料連接配接的請求後,連接配接初始化成功後,接着向Modem發起建立資料連接配接的請求,并把狀态機的狀态切換至DcActivating,表示目前正在建立資料:

private class DcInactiveState extends State {
            ....

            @Override
            public boolean processMessage(Message msg) {
                boolean retVal;

                switch (msg.what) {
                    ....
                    // 網絡連接配接請求
                    case EVENT_CONNECT:
                        ConnectionParams cp = (ConnectionParams) msg.obj;
                        // 初始化連接配接
                        if (initConnection(cp)) {
                            //向Modem發送資料連接配接請求
                            onConnect(mConnectionParams);
                            //狀态切換至Activating
                            transitionTo(mActivatingState);
                        } else {
                            notifyConnectCompleted(cp, DcFailCause.UNACCEPTABLE_NETWORK_PARAMETER,
                                    false);
                        }
                        retVal = HANDLED;
                        break;
                    ....
                    default:
                        retVal = NOT_HANDLED;
                        break;
                }
                return retVal;
    }
           

等Modem建立資料連接配接後,Telephony收到建立成功的消息,發送給

DataConnection

,目前狀态

DcActivatingState

負責處理該消息,若沒有錯誤,則直接切換至Active狀态:

// state machine is activating a connection
    private class DcActivatingState extends State {
        @Override
        public boolean processMessage(Message msg) {
            boolean retVal;
            AsyncResult ar;
            ConnectionParams cp;

            switch (msg.what) {
                ....
                case EVENT_SETUP_DATA_CONNECTION_DONE:
                    ar = (AsyncResult) msg.obj;
                    cp = (ConnectionParams) ar.userObj;

                    DataCallResponse.SetupResult result = onSetupConnectionCompleted(ar);

                    switch (result) {
                        case SUCCESS:
                            // All is well,切換至Active狀态
                            ...
                            mDcFailCause = DcFailCause.NONE;
                            transitionTo(mActiveState);
                            break;
                        // 各種錯誤處理
                        case ERR_xxxx
                            ...
                            break;
                }
                default:
                    retVal = NOT_HANDLED;
                    break;
            }
            return retVal;
        }
    }

           
有關Android的StateMachine可參考: /android/frameworks/base/core/java/com/android/internal/util/StateMachine.java

狀态機進入到active狀态,此時表示資料連接配接建立成功,最後建立一個

NetworkAgent

對象,并将該對象注冊到

ConnectivitySerice

:

private class DcActiveState extends State {
        @Override public void enter() {
            if (mConnectionParams != null) {
                ApnContext apnContext = mConnectionParams.mApnContext;
                int network = ConnectivityManager.TYPE_NONE;
                // 根據APN設定網絡類型
                switch(apnContext.getApnType()) {
                    case PhoneConstants.APN_TYPE_IMS:
                        network = ConnectivityManager.TYPE_MOBILE_IMS;
                        break;
                    case PhoneConstants.APN_TYPE_EMERGENCY:
                        network = ConnectivityManager.TYPE_MOBILE_EMERGENCY;
                        break;
                    default:
                        network = ConnectivityManager.TYPE_MOBILE;
                        break;
                }
                if ((network != ConnectivityManager.TYPE_NONE) && (network != mNetworkInfo.getType())) {
                    mNetworkInfo.setType(network);
                }
            }

            boolean createNetworkAgent = true;
            ....

            mDcController.addActiveDcByCid(DataConnection.this);

            mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED,
                    mNetworkInfo.getReason(), null);
            ....
            final NetworkMisc misc = new NetworkMisc();
            misc.subscriberId = mPhone.getSubscriberId();
            // 建立NetworkAgent,并向ConnectivityService注冊該代理對象
            if (createNetworkAgent) {
                mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
                        "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties,
                        , misc);
            }
        }
    }

           

ConnectivityService

注冊

DcNetworkAgent

,并将目前網絡連接配接資訊發送給

ConnectivityService

,同時發送一個包含了該代理對象的

Messager

用于與

ConnectivityService

之間的資料交換:

public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
            NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
        super(looper);
        mContext = context;
        if (ni == null || nc == null || lp == null) {
            throw new IllegalArgumentException();
        }
        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
                Context.CONNECTIVITY_SERVICE);
        //注冊NetworkAgent
        netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
                new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
    }
           

ConnectivityService

注冊NetworkAgent,生成一個可用的網絡ID;

mHandler

接收到消息後,在

mTrackerHandler

(跟蹤網絡狀态)與

DcNetworkAgent

之間建立一個異步通信通道,并更新網絡狀态:

public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
                LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
                int currentScore, NetworkMisc networkMisc) {
            enforceConnectivityInternalPermission();
            // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
            // satisfies mDefaultRequest.

            // if exist, just return netid value
            synchronized (mNetworkForNetId) {
                if (mNetworkForNetId.get(netid) != null) {
                    return netid;
                }
            }

            final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                    new Network(reserveNetId()), new NetworkInfo(networkInfo), new LinkProperties(
                    linkProperties), new NetworkCapabilities(networkCapabilities), currentScore,
                    mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
            synchronized (this) {
                nai.networkMonitor.systemReady = mSystemReady;
            }

            mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
            return nai.network.netId;
        }

        // mHandler接收到消息後,調用該函數進行處理
        private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
            mNetworkAgentInfos.put(na.messenger, na);

            synchronized (mNetworkForNetId) {
                mNetworkForNetId.put(na.network.netId, na);
            }
            // 建立mTrackHandler與DcNetworkAgent之間的通信通道
            na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
            NetworkInfo networkInfo = na.networkInfo;
            na.networkInfo = null;
            // 更新網絡狀态
            updateNetworkInfo(na, networkInfo);
        }
           

更新網絡狀态:

  • 如果Netd尚未建立對應的實體連結,則建立NetworkInfo對應的實體網絡連接配接;
  • 更新網絡連接配接屬性,信号強度,重新比對目前網絡與網絡請求;
  • 通知注冊了回調的監聽者網絡狀态資訊;
private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) {
            if(DBG) Log.e(TAG, "updateNetworkInfo()");
            NetworkInfo.State state = newInfo.getState();
            NetworkInfo oldInfo = null;
            final int oldScore = networkAgent.getCurrentScore();
            boolean isSuspendedToConnected = false;
            ....
            // Netd尚未建立NetworkInfo對應的實體網絡連結
            if (state == NetworkInfo.State.CONNECTED && (!networkAgent.created || isSuspendedToConnected)) {
                if ((networkAgent.networkInfo.getType() != ConnectivityManager.TYPE_WIFI)
                        && !networkAgent.created) {
                    try {
                        // This should never fail.  Specifying an already in use NetID will cause failure.
                        if (networkAgent.isVPN()) {
                            mNetd.createVirtualNetwork(networkAgent.network.netId,
                                    !networkAgent.linkProperties.getDnsServers().isEmpty(),
                                    (networkAgent.networkMisc == null ||
                                        !networkAgent.networkMisc.allowBypass));
                        } else {
                            mNetd.createPhysicalNetwork(networkAgent.network.netId,
                                networkAgent.networkCapabilities.hasCapability(
                                        NET_CAPABILITY_NOT_RESTRICTED) ?
                                        null : NetworkManagementService.PERMISSION_SYSTEM);
                        }
                    } catch (Exception e) {
                        loge("Error creating network " + networkAgent.network.netId + ": "
                                + e.getMessage());
                        return;
                    }
                }

                networkAgent.created = true;
                updateLinkProperties(networkAgent, null);
                notifyIfacesChanged();
                networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);

                updateSignalStrengthThresholds(networkAgent, "CONNECT", null);

                // Consider network even though it is not yet validated.
                rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP);

                // This has to happen after matching the requests, because callbacks are just requests.
                notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK);
            }else if{....}
    }
           

ConnectivityService

向Telephony發送網絡請求

上層需要使用特定的網絡時,比如發送彩信(MMS)需要用到MMS網絡;使用視訊通話(Volte)需要使用IMS網絡,都會向

ConnectivityService

發送網絡請求,建立相應的網絡連接配接,而

ConnectivityService

則會将這些網絡請求發給Telephony,由其負責網絡連接配接的建立。這裡,就來看一看網絡請求的處理過程。

在Telephony建立

DctController

的時候,建立一個

TelephonyNetworkFactory

用于接收來自

ConnectivityService

的網絡請求,并将其注冊到

ConnectivityService

中:

private void updatePhoneBaseForIndex(int index, PhoneBase phoneBase) {
        ....
        mNetworkFactory[index] = new TelephonyNetworkFactory(this.getLooper(),
                mPhones[index].getContext(), "TelephonyNetworkFactory", phoneBase,
                mNetworkFilter[index]);
        mNetworkFactory[index].setScoreFilter();
        mNetworkFactoryMessenger[index] = new Messenger(mNetworkFactory[index]);
        cm.registerNetworkFactory(mNetworkFactoryMessenger[index], "Telephony");
    }
           

ConnectivityService将包含了

TelephonyNetworkFactory

的消息傳遞類Messager打包成一個

NetworkFactoryInfo

,将其注冊到系統中:

@Override
    public void registerNetworkFactory(Messenger messenger, String name) {
        enforceConnectivityInternalPermission();
        NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel());
        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
    }
           

ConnectivityService

的内部類

NetworkStateTracker

TelephonyNetworkFactory

之間建立一個異步通信的通道,這樣兩者就可以互相發送消息了。

private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
        if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
        mNetworkFactoryInfos.put(nfi.messenger, nfi);
        nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
    }
           

此後,APP向

ConnectivityService

發送網絡請求,則

ConnectivityService

将請求打包成一個

NetworkRequestInfo

準備發送給NetworkFactory:

@Override
    public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
            Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
        networkCapabilities = new NetworkCapabilities(networkCapabilities);
        enforceNetworkRequestPermissions(networkCapabilities);
        enforceMeteredApnPolicy(networkCapabilities);
        ensureRequestableCapabilities(networkCapabilities);

        if (timeoutMs <  || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
            throw new IllegalArgumentException("Bad timeout specified");
        }

        NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                nextNetworkRequestId());
        NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,NetworkRequestInfo.REQUEST);

        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
        if (timeoutMs > ) {
            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
                    nri), timeoutMs);
        }
        return networkRequest;
    }

           

處理網絡請求,首先比對目前網絡請求與網絡,然後将該網絡請求發送到NetworkFactory:

private void handleRegisterNetworkRequest(NetworkRequestInfo nri) {
            mNetworkRequests.put(nri.request, nri);
            // 比對所有網絡與網絡請求
            rematchAllNetworksAndRequests(null, );
            if (nri.isRequest && mNetworkForRequestId.get(nri.request.requestId) == null) {
                // 發送更新後的網絡評分(網絡的優先級)到NetworkFactory
                sendUpdatedScoreToFactories(nri.request, );
            }
        }

           

将網絡請求發送給所有已注冊的NetworkFactory:

private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) {
        //通過異步通信通道向所有NetworkFactory發送網絡請求
        for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
            nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, ,
                    networkRequest);
        }
    }

           

NetworkFactory接收到網絡請求

CMD_REQUEST_NETWORK

:

protected void handleAddRequest(NetworkRequest request, int score) {
        NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
        if (n == null) {
            if (DBG) log("got request " + request + " with score " + score);
            n = new NetworkRequestInfo(request, score);
            mNetworkRequests.put(n.request.requestId, n);
        } else {
            n.score = score;
        }
        // 評估該網絡請求
        evalRequest(n);
    }
           

評估網絡請求是否滿足處理的條件:

private void evalRequest(NetworkRequestInfo n) {
            if (n.requested == false && n.score < mScore && (n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) && acceptRequest(n.request, n.score))) {
                // 處理網絡請求
                needNetworkFor(n.request, n.score);
                n.requested = true;
            } else if (n.requested == true &&
                (n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) == false ||
                acceptRequest(n.request, n.score) == false)) {
                ....
                } else {
                    releaseNetworkFor(n.request);
                    n.requested = false;
                }
            }
        }


     @Override
        protected void needNetworkFor(NetworkRequest networkRequest, int score) {
            // figure out the apn type and enable it
            log("Cellular needs Network for " + networkRequest);

            if (getRequestPhoneId(networkRequest) == mPhone.getPhoneId()) {
                DcTrackerBase dcTracker =((PhoneBase)mPhone).mDcTracker;
                // 擷取APN
                String apn = apnForNetworkRequest(networkRequest);
                // 是否支援對應的APN
                if (dcTracker.isApnSupported(apn)) {
                    requestNetwork(networkRequest, dcTracker.getApnPriority(apn), l);
                } 
            } else {
                // 将NetworkRequest放入緩沖隊列
                mPendingReq.put(networkRequest.requestId, networkRequest);
            }
        }
           

調用

DctController

requestNetwork

函數,請求建立相應的網絡連接配接:

private int requestNetwork(NetworkRequest request, int priority, LocalLog l) {
        logd("requestNetwork request=" + request + ", priority=" + priority);
        // 儲存網絡請求資訊
        RequestInfo requestInfo = new RequestInfo(request, priority, l);
        mRequestInfos.put(request.requestId, requestInfo);
        // 處理網絡請求
        processRequests();

        return PhoneConstants.APN_REQUEST_STARTED;
    }

           

繼續閱讀