Android 网络管家ConnectivityManager

Posted Jason_Wang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(-1, 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通过DcNetworkAgentConnectivityService发送消息,告知其网络信息。初始化时,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,
                        50, 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(50);
        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的内部类NetworkStateTrackerTelephonyNetworkFactory之间建立一个异步通信的通道,这样两者就可以相互发送消息了。


    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 < 0 || 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 > 0) 
            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, 0);
            if (nri.isRequest && mNetworkForRequestId.get(nri.request.requestId) == null) 
                // 发送更新后的网络评分(网络的优先级)到NetworkFactory
                sendUpdatedScoreToFactories(nri.request, 0);
            
        

将网络请求发送给所有已注册的NetworkFactory:


    private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) 
        //通过异步通信通道向所有NetworkFactory发送网络请求
        for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) 
            nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0,
                    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);
            
        

调用DctControllerrequestNetwork函数,请求建立相应的网络连接:


    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;
    

以上是关于Android 网络管家ConnectivityManager的主要内容,如果未能解决你的问题,请参考以下文章

Android 网络管家ConnectivityManager

我的手机管家(11) 网络助手 界面设计及适配器

如何在单击按钮时在android中从3G切换到2G

我的手机管家 主界面

QQ浏览器弹出“电脑管家云安全中心提醒您,该网站可能存在OpenSSL“心血”漏洞!”如何关掉

我的手机管家病毒扫描 界面设计