AndroidP 4G网络架构--与ConnectivityService通信

人走茶凉 提交于 2020-02-28 17:05:03

1、创建

Android9.0 开启关闭移动数据流程帖子中,提到了数据的打开过程,会调用DcAsyncChannel的bringUp方法。
@DcTracker
    private boolean setupData(ApnContext apnContext, int radioTech, boolean unmeteredUseOnly) {
        //用于连接DcTracker和DataConnection
        DcAsyncChannel dcac = null;
  ...
        if (dcac == null) {
        ...
           //判断能否复用dataConnection
            dcac = findFreeDataConnection();
            if (dcac == null) {
               //不能复用创建新的DataConnection和DcAsyncChannel
                dcac = createDataConnection();
            }
  }
  ...
        apnContext.setDataConnectionAc(dcac);
        apnContext.setApnSetting(apnSetting);
        apnContext.setState(DctConstants.State.CONNECTING);
        mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
        Message msg = obtainMessage();
        msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
        msg.obj = new Pair<ApnContext, Integer>(apnContext, generation);
        dcac.bringUp(apnContext, profileId, radioTech, unmeteredUseOnly, msg, generation);
}

这里我们详细看一下createDataConnection方法。

@DcTracker

    private DcAsyncChannel createDataConnection() {

        if (DBG) log("createDataConnection E");
 
        int id = mUniqueIdGenerator.getAndIncrement();
        DataConnection conn = DataConnection.makeDataConnection(mPhone, id, this,
                mDataServiceManager, mDcTesterFailBringUpAll, mDcc);
        mDataConnections.put(id, conn);
       DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG);
 
        //mark一下,后面详解
         int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());


        if (status == AsyncChannel.STATUS_SUCCESSFUL) {
            mDataConnectionAcHashMap.put(dcac.getDataConnectionIdSync(), dcac);
        } else {
            loge("createDataConnection: Could not connect to dcac=" + dcac + " status=" + status);
        }

 

        if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn);
        return dcac;
    }
这里首先创建DcAsyncChannel实例,并调用fullyConnectSync方法,目的是完成DcTracker与DataConnection之间handle的绑定,为什么这样绑定,后续介绍。
即:传递的参数this把DcTracker自己传递给AsyncChannel与DataConnection的getHandler获取handle进行绑定

在DataConnection中,当数据连接成功时,就会在DataConnection中进入DcActiveState的状态机,然后就会创建数据连接随想DcNetworkAgent。
@DataConnection.java
    private class DcActiveState extends State {
        @Override
         public void enter() {
            ...
            updateNetworkInfo();
            ...
            if (DBG) log("mRestrictedNetworkOverride = " + mRestrictedNetworkOverride);
            mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
                    "DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties,
                    50, misc);
            ...
        }
}
这里创建DcNetworkAgent实例,DcNetworkAgent是NetworkAgent的子类,初始化DcNetworkAgent时就会初始化NetworkAgent
所以进入NetworkAgent类
@NetworkAgent.java
    public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
            NetworkCapabilities nc, LinkProperties lp, int score, NetworkMisc misc) {
        super(looper);
        LOG_TAG = logTag;
        mContext = context;
        if (ni == null || nc == null || lp == null) {
            throw new IllegalArgumentException();
        }
        if (VDBG) log("Registering NetworkAgent");
        ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
                Context.CONNECTIVITY_SERVICE);
        netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
                new LinkProperties(lp), new NetworkCapabilities(nc), score, misc);
    }
在NetworkAgent的初始化时,只做了一件事,就是将其注册到ConnectivityService中。

至此 DcAsyncChannel,DcNetworkAgent,NetworkAgent,ConnectivityManager都初始化完了
 
2、连接
 
上面提到 NetworkAgent将其注册到ConnectivityService中。而这里传递的参数包含当前NetworkAgent的Messenger,
NetworkAgent用于与ConnectivityService之间建立AsyncChannel通道。
看一下在 ConnectivityService中的注册过程:
@ConnectivityService.java
    public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
            LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
            int currentScore, NetworkMisc networkMisc) {
        enforceConnectivityInternalPermission();
        LinkProperties lp = new LinkProperties(linkProperties);
        lp.ensureDirectlyConnectedRoutes();
        // TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
        // satisfies mDefaultRequest.
        final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
        final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
                mContext, mTrackerHandler, new NetworkMisc(networkMisc), mDefaultRequest, this);
        // Make sure the network capabilities reflect what the agent info says.
        nai.networkCapabilities = mixInCapabilities(nai, nc);
        synchronized (this) {
            nai.networkMonitor.systemReady = mSystemReady;
        }
        final String extraInfo = networkInfo.getExtraInfo();
        final String name = TextUtils.isEmpty(extraInfo)
                ? nai.networkCapabilities.getSSID() : extraInfo;
        addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network, name);
        if (DBG) log("registerNetworkAgent " + nai);
        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
        return nai.network.netId;
    }
上面代码可以看到,当NetworkAgent注册时,在ConnectivityService内部创建了一个新的对象NetworkAgentInfo,该对象保留了传递进来的一系列参数,并且new AsyncChanel通道用于通信。
最后把当前创建的NetworkAgentInfo对象放到EVENT_REGISTER_NETWORK_AGENT消息中,发送给handler处理。
@ConnectivityService.java
    private class InternalHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
    ...
    case EVENT_REGISTER_NETWORK_AGENT: {
                    handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
                    break;
                }
    ...
}

 
    private void handleRegisterNetworkAgent(NetworkAgentInfo nai) {
        if (VDBG) log("Got NetworkAgent Messenger");
        mNetworkAgentInfos.put(nai.messenger, nai);
        synchronized (mNetworkForNetId) {
            mNetworkForNetId.put(nai.network.netId, nai);
        }
        nai.asyncChannel.connect(mContext, mTrackerHandler, nai.messenger);
        NetworkInfo networkInfo = nai.networkInfo;
        nai.networkInfo = null;
        updateNetworkInfo(nai, networkInfo);
        updateUids(nai, null, nai.networkCapabilities);
    }
 
这里ConnectivityService利用刚才创建的AsyncChanel向NetworkAgent发起单向连接请求
根据AsyncChanel的原理,此时ConnectivityService发起的是单向的AsyncChanel连接,发起后将会在mTrackerHandler中收到CMD_CHANNEL_HALF_CONNECTED消息:
 
@ConnectivityService.java
    private class NetworkStateTrackerHandler extends Handler {
 
        private boolean maybeHandleAsyncChannelMessage(Message msg) {
            switch (msg.what) {
                default:
                    return false;
                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
                    handleAsyncChannelHalfConnect(msg);
                    break;
                }
                ...
            }
            return true;
        }
...
}
    private void handleAsyncChannelHalfConnect(Message msg) {
        AsyncChannel ac = (AsyncChannel) msg.obj;
        if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
            ...
        } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) {
            if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                if (VDBG) log("NetworkAgent connected");
                // A network agent has requested a connection.  Establish the connection.
                mNetworkAgentInfos.get(msg.replyTo).asyncChannel.
                        sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
            } else {
                ...
            }
        }
    }
上面代码可以看到,当ConnectivityService与NetworkAgent之间单向通道建立完成后,又发起了双向通道的请求,此时在NetworkAgent端,将会收到CMD_CHANNEL_FULL_CONNECTION的请求消息:
@NetworkAgent.java
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
                if (mAsyncChannel != null) {
                    log("Received new connection while already connected!");
                } else {
                    if (VDBG) log("NetworkAgent fully connected");
                    AsyncChannel ac = new AsyncChannel();
                    ac.connected(null, this, msg.replyTo);
                    //连接建立成功
                    ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
                            AsyncChannel.STATUS_SUCCESSFUL);
                    synchronized (mPreConnectedQueue) {
                        mAsyncChannel = ac;
                        for (Message m : mPreConnectedQueue) {
                            ac.sendMessage(m);
                        }
                        mPreConnectedQueue.clear();
                    }
                }
                break;
            }
  ...
}
从上面的代码可以看出,NetworkAgent收到请求之后就发送了建立成功的消息,然后检测消息队列,如果有消息就及时向ConnectivityService传递。
至此,NetworkAgent与ConnectivityService建立连接完成。别忘了NetworkAgent是通过DataConnection在onConnection连接成功后创建的,
所以,DataConnection通过调用DcNetworkAgent(NetworkAgent)方法,例如sendNetworkInfo()方法,NetworkAgent通过建立的AsyncChannel连接调用sendMessage发送给ConnectivityService。


最后看一下最开始mark的位置。
DcTracker在创建DataConnection时,调用
         DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG);
        int status = dcac. fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
根据AsyncChannel规则,服务端会收到CMD_CHANNEL_FULL_CONNECTION连接通知:
@DataConnection.java
    private class DcDefaultState extends State {
        @Override
        public boolean processMessage(Message msg) {
            switch (msg.what) {
                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
                    if (mAc != null) {
                        if (VDBG) log("Disconnecting to previous connection mAc=" + mAc);
                        mAc.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
                                AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED);
                    } else {
                        mAc = new AsyncChannel();
                        mAc. connected(null, getHandler(), msg.replyTo);
                        if (VDBG) log("DcDefaultState: FULL_CONNECTION reply connected");
                        mAc. replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
                                AsyncChannel.STATUS_SUCCESSFUL, mId, "hi");
                    }
                    break;
                }
   ...
  }
}
从上面代码可以看到,DataConnection在最开始的状态机DcDefaultState中就处理了CMD_CHANNEL_FULL_CONNECTION通知,并且和NetworkAgent与ConnectivityService建立的连接一样,
首先创建AsyncChannel,返回连接建立成功的消息。所以DcTracker与DataConnection也是双向连接。
至此,DcTracker调用DcAsyncChannel的bingUp方法,就是DcTracker通过AsyncChannel连接,调用sendMessage方法发送给DataConnection。

 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!