Android -- NetworkFactory与NetworkAgent的通信机制
转自write.blog.youkuaiyun.com/postedit
在上一篇博文中讲到,EthernetNetworkFactory包揽了Ethernet所有的网络管理操作,这其中就包含怎么样通知ConnectifyService(下文都简称CS)网络状态发生变化。接下来,我们借助有线网络来简要介绍Android 4.4之后,网络模块是怎样与CS通信并进行网络管理的。
在启动Ethernet网络服务时,我们会对Ethernet做一些初始化操作,以方便我们进行网络管理。看EthernetNetworkFactory::start()方法:
start()方法接受一个Handler对象作为参数,该参数是在EthernetServiceImpl::start()中传入的,它新建了一个HandlerThread对象,并传入作为参数,从这可知网络管理的操作是运行在EthernetServiceImpl线程中的。
- /**
- * Begin monitoring connectivity
- */
- public synchronized void start(Context context, Handler target) {
- // The services we use.
- IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
- mNMService = INetworkManagementService.Stub.asInterface(b);
- mEthernetManager = (EthernetManager) context.getSystemService(Context.ETHERNET_SERVICE);
- // Interface match regex.
- mIfaceMatch = context.getResources().getString(
- com.android.internal.R.string.config_ethernet_iface_regex);
- // Create and register our NetworkFactory.
- mFactory = new LocalNetworkFactory(NETWORK_TYPE, context, target.getLooper());
- mFactory.setCapabilityFilter(mNetworkCapabilities);
- mFactory.setScoreFilter(-1); // this set high when we have an iface
- mFactory.register();
- mContext = context;
- // Start tracking interface change events.
- mInterfaceObserver = new InterfaceObserver();
- try {
- mNMService.registerObserver(mInterfaceObserver);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not register InterfaceObserver " + e);
- }
- // If an Ethernet interface is already connected, start tracking that.
- // Otherwise, the first Ethernet interface to appear will be tracked.
- try {
- final String[] ifaces = mNMService.listInterfaces();
- for (String iface : ifaces) {
- synchronized(this) {
- if (maybeTrackInterface(iface)) {
- // We have our interface. Track it.
- // Note: if the interface already has link (e.g., if we
- // crashed and got restarted while it was running),
- // we need to fake a link up notification so we start
- // configuring it. Since we're already holding the lock,
- // any real link up/down notification will only arrive
- // after we've done this.
- if (mNMService.getInterfaceConfig(iface).hasFlag("running")) {
- updateInterfaceState(iface, true);
- }
- break;
- }
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Could not get list of interfaces " + e);
- }
- }
代码中创建了一个LocalNetworkFactory对象。LocalNetworkFactory继承自NetworkFactory:
NetworkFactory继承自Handler,我们可以把它动作一个工厂,对网络的请求和终止操作都通过该对象进行处理。从注释可知NetworkFactory与NetworkAgent对象有密切关系,它通过register()方法向CS进行注册。start/stopNetwork()是提供的回调函数 ,我们可以通过这两个函数来请求或终止网络:
- /**
- * A NetworkFactory is an entity that creates NetworkAgent objects.
- * The bearers register with ConnectivityService using {@link #register} and
- * their factory will start receiving scored NetworkRequests. NetworkRequests
- * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by
- * overridden function. All of these can be dynamic - changing NetworkCapabilities
- * or score forces re-evaluation of all current requests.
- *
- * If any requests pass the filter some overrideable functions will be called.
- * If the bearer only cares about very simple start/stopNetwork callbacks, those
- * functions can be overridden. If the bearer needs more interaction, it can
- * override addNetworkRequest and removeNetworkRequest which will give it each
- * request that passes their current filters.
- * @hide
- **/
- public class NetworkFactory extends Handler {
- ...
- public NetworkFactory(Looper looper, Context context, String logTag,
- NetworkCapabilities filter) {
- super(looper);
- LOG_TAG = logTag;
- mContext = context;
- mCapabilityFilter = filter;
- }
- ...
- public void register() {
- if (DBG) log("Registering NetworkFactory");
- if (mMessenger == null) {
- mMessenger = new Messenger(this);
- ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
- }
- }
- ...
- // override to do simple mode (request independent)
- protected void startNetwork() { }
- protected void stopNetwork() { }
- ...
- }
- public void register() {
- if (DBG) log("Registering NetworkFactory");
- if (mMessenger == null) {
- mMessenger = new Messenger(this);
- ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);
- }
- }
- @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));
- }
- case EVENT_REGISTER_NETWORK_FACTORY: {
- handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj);
- break;
- }
- 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);
- }
- /**
- * Connect handler and messenger.
- *
- * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
- * msg.arg1 = status
- * msg.obj = the AsyncChannel
- *
- * @param srcContext
- * @param srcHandler
- * @param dstMessenger
- */
- public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
- if (DBG) log("connect srcHandler to the dstMessenger E");
- // We are connected
- connected(srcContext, srcHandler, dstMessenger);
- // Tell source we are half connected
- replyHalfConnected(STATUS_SUCCESSFUL);
- if (DBG) log("connect srcHandler to the dstMessenger X");
- }
- /**
- * Connect handler to messenger. This method is typically called
- * when a server receives a CMD_CHANNEL_FULL_CONNECTION request
- * and initializes the internal instance variables to allow communication
- * with the dstMessenger.
- *
- * @param srcContext
- * @param srcHandler
- * @param dstMessenger
- */
- public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
- if (DBG) log("connected srcHandler to the dstMessenger E");
- // Initialize source fields
- mSrcContext = srcContext;
- mSrcHandler = srcHandler;
- mSrcMessenger = new Messenger(mSrcHandler);
- // Initialize destination fields
- mDstMessenger = dstMessenger;
- if (DBG) log("connected srcHandler to the dstMessenger X");
- }
- /**
- * Reply to the src handler that we're half connected.
- * see: CMD_CHANNEL_HALF_CONNECTED for message contents
- *
- * @param status to be stored in msg.arg1
- */
- private void replyHalfConnected(int status) {
- Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
- msg.arg1 = status;
- msg.obj = this;
- msg.replyTo = mDstMessenger;
- /*
- * Link to death only when bindService isn't used.
- */
- if (mConnection == null) {
- mDeathMonitor = new DeathMonitor();
- try {
- mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);//为了防止AsyncChannel用于不同进程通信时,若Server端所在的进程已经死掉,来通知
- //Client端进程进行一些后期处理
- } catch (RemoteException e) {
- mDeathMonitor = null;
- // Override status to indicate failure
- msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
- }
- }
- mSrcHandler.sendMessage(msg);
- }
- case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
- handleAsyncChannelHalfConnect(msg);
- break;
- }
- private void handleAsyncChannelHalfConnect(Message msg) {
- AsyncChannel ac = (AsyncChannel) msg.obj;
- if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
- if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
- if (VDBG) log("NetworkFactory connected");
- // A network factory has connected. Send it all current NetworkRequests.
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.isRequest == false) continue;
- NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
- ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
- (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
- }
- } else {
- loge("Error connecting NetworkFactory");
- mNetworkFactoryInfos.remove(msg.obj);
- }
- } 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 {
- loge("Error connecting NetworkAgent");
- NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo);
- if (nai != null) {
- final boolean wasDefault = isDefaultNetwork(nai);
- synchronized (mNetworkForNetId) {
- mNetworkForNetId.remove(nai.network.netId);
- mNetIdInUse.delete(nai.network.netId);
- }
- // Just in case.
- mLegacyTypeTracker.remove(nai, wasDefault);
- }
- }
- }
- }
- // A network factory has connected. Send it all current NetworkRequests.
- for (NetworkRequestInfo nri : mNetworkRequests.values()) {
- if (nri.isRequest == false) continue;
- NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
- ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
- (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
- }
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case CMD_REQUEST_NETWORK: {
- handleAddRequest((NetworkRequest)msg.obj, msg.arg1);
- break;
- }
- case CMD_CANCEL_REQUEST: {
- handleRemoveRequest((NetworkRequest) msg.obj);
- break;
- }
- case CMD_SET_SCORE: {
- handleSetScore(msg.arg1);
- break;
- }
- case CMD_SET_FILTER: {
- handleSetFilter((NetworkCapabilities) msg.obj);
- break;
- }
- }
- }
- private 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 {
- if (VDBG) log("new score " + score + " for exisiting request " + request);
- n.score = score;
- }
- if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter);
- evalRequest(n);
- }
- private void evalRequest(NetworkRequestInfo n) {
- if (VDBG) log("evalRequest");
- if (n.requested == false && n.score < mScore &&
- n.request.networkCapabilities.satisfiedByNetworkCapabilities(
- mCapabilityFilter) && acceptRequest(n.request, n.score)) {
- if (VDBG) log(" needNetworkFor");
- 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)) {
- if (VDBG) log(" releaseNetworkFor");
- releaseNetworkFor(n.request);
- n.requested = false;
- } else {
- if (VDBG) log(" done");
- }
- }
- // override to do fancier stuff
- protected void needNetworkFor(NetworkRequest networkRequest, int score) {
- if (++mRefCount == 1) startNetwork();
- }
- protected void releaseNetworkFor(NetworkRequest networkRequest) {
- if (--mRefCount == 0) stopNetwork();
- }
- private class LocalNetworkFactory extends NetworkFactory {
- LocalNetworkFactory(String name, Context context, Looper looper) {
- super(looper, context, name, new NetworkCapabilities());
- }
- protected void startNetwork() {
- onRequestNetwork();
- }
- protected void stopNetwork() {
- }
- }
我们看onRequestNetwork()方法来触发一个网络的连接:
CS中处理网络更新的Handler是NetworkStateTrackerHandler。当网络连接后,通知CS更新网络的操作则是通过NetworkAgent对象进行的。从它的定义可知,它也是一个Handler:
- /* Called by the NetworkFactory on the handler thread. */
- public void onRequestNetwork() {
- // TODO: Handle DHCP renew.
- Thread dhcpThread = new Thread(new Runnable() {
- public void run() {
- if (DBG) Log.i(TAG, "dhcpThread(" + mIface + "): mNetworkInfo=" + mNetworkInfo);
- LinkProperties linkProperties;
- IpConfiguration config = mEthernetManager.getConfiguration();
- if (config.getIpAssignment() == IpAssignment.STATIC) {
- if (!setStaticIpAddress(config.getStaticIpConfiguration())) {
- // We've already logged an error.
- return;
- }
- linkProperties = config.getStaticIpConfiguration().toLinkProperties(mIface);
- } else {
- mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr);
- DhcpResults dhcpResults = new DhcpResults();
- // TODO: Handle DHCP renewals better.
- // In general runDhcp handles DHCP renewals for us, because
- // the dhcp client stays running, but if the renewal fails,
- // we will lose our IP address and connectivity without
- // noticing.
- if (!NetworkUtils.runDhcp(mIface, dhcpResults)) {
- Log.e(TAG, "DHCP request error:" + NetworkUtils.getDhcpError());
- // set our score lower than any network could go
- // so we get dropped.
- mFactory.setScoreFilter(-1);
- // If DHCP timed out (as opposed to failing), the DHCP client will still be
- // running, because in M we changed its timeout to infinite. Stop it now.
- NetworkUtils.stopDhcp(mIface);
- return;
- }
- linkProperties = dhcpResults.toLinkProperties(mIface);
- }
- ...
- }
- });
- dhcpThread.start();
- }
- synchronized(EthernetNetworkFactory.this) {
- if (mNetworkAgent != null) {
- Log.e(TAG, "Already have a NetworkAgent - aborting new request");
- return;
- }
- mLinkProperties = linkProperties;
- mNetworkInfo.setIsAvailable(true);
- mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
- // Create our NetworkAgent.
- mNetworkAgent = new NetworkAgent(mFactory.getLooper(), mContext,
- NETWORK_TYPE, mNetworkInfo, mNetworkCapabilities, mLinkProperties,
- NETWORK_SCORE) {
- public void unwanted() {
- synchronized(EthernetNetworkFactory.this) {
- if (this == mNetworkAgent) {
- NetworkUtils.stopDhcp(mIface);
- mLinkProperties.clear();
- mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null,
- mHwAddr);
- updateAgent();
- mNetworkAgent = null;
- try {
- mNMService.clearInterfaceAddresses(mIface);
- } catch (Exception e) {
- Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
- }
- } else {
- Log.d(TAG, "Ignoring unwanted as we have a more modern " +
- "instance");
- }
- }
- };
- };
- }
- /**
- * Called when ConnectivityService has indicated they no longer want this network.
- * The parent factory should (previously) have received indication of the change
- * as well, either canceling NetworkRequests or altering their score such that this
- * network won't be immediately requested again.
- */
- abstract protected void unwanted();
既然网络状态的变化是由NetworkAgent处理的,那我们就接着看NetworkAgent是怎么跟CS通信的:
在创建NetworkAgent对象时,接受一个特定的Looper对象,并向CS注册该NetworkAgent对象,这与LocalNetworkFactory的处理类似。看CS中具体的注册处理:
这里的Messager对象是NetworkAgent对象自身的一个引用,创建对应的NetworkAgentInfo对象,其内部创建了一个AsyncChannel对象;messenger参数前面介绍过,mTrackderHandler是NetworkStateTrackerHandler的一个实例。向InternalHandler发送EVENT_REGISTER_NETWORK_AGENT消息,处理注册操作。看CS中的处理:
也是将na和messenger对象保存到一个HashMap集合中,也是通过AsyncChannel进行通信,也是调用connect()进行连接,这跟前面所述的NetworkFactory的处理基本类似。从前面的分析可知这个AsyncChannel对象中,mSrcHandler和mSrcMessenger指向一个CS中的NetworkStateTrackerHandler,mDstMessenger指向要注册的NetworkAgent对象,因为它本身也是个Handler。接着向mSrcHandler发送CMD_CHANNEL_HALF_CONNECTED消息,同样也是handleAsyncChannelHalfConnect()处理,只不过走的处理分支不同,有前面的介绍可知:
使用AsyncChannel向mDstMessenger发送CMD_CHANNEL_FULL_CONNECTION消息,即向NetworkAgent对象发送该消息:
如果当前NetworkAgent是第一次进行连接,mAsyncChannel为null;新建一个AsyncChannel对象,调用connected()进行FULL_CONNECTION:
mSrcHandler和mSrcMessenger指向当前的NetworkAgent对象;mDstMessenger指向CS中的NetworkStateTrackerHandler对象。随后再发送CMD_CHANNEL_FULLY_CONNECTED消息,表示整个AsyncChannel的连接成功,可以进行通信了。同时,还会遍历mPreConnectedQueue集合,这个集合中保存了当mAsyncChannel为null时的所有与更新网络信息相关的message,通过ac.sendMessage()向CS发送所有的message进行状态更新(要注意,ac对象的mSrcHanlder为当前NetworkAgent,mDstMessenger指向NetworkStateTrackerHandler)。
- public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
- NetworkCapabilities nc, LinkProperties lp, int score) {
- this(looper, context, logTag, ni, nc, lp, score, null);
- }
- 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);
- }
- 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.
- 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;
- }
- addValidationLogs(nai.networkMonitor.getValidationLogs(), nai.network);
- if (DBG) log("registerNetworkAgent " + nai);
- mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
- return nai.network.netId;
- }
- case EVENT_REGISTER_NETWORK_AGENT: {
- handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj);
- break;
- }
- private void handleRegisterNetworkAgent(NetworkAgentInfo na) {
- if (VDBG) log("Got NetworkAgent Messenger");
- mNetworkAgentInfos.put(na.messenger, na);
- synchronized (mNetworkForNetId) {
- mNetworkForNetId.put(na.network.netId, na);
- }
- na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger);
- NetworkInfo networkInfo = na.networkInfo;
- na.networkInfo = null;
- updateNetworkInfo(na, networkInfo);//更新网络状态的函数
- }
- 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);
- 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;
- }
- public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
- if (DBG) log("connected srcHandler to the dstMessenger E");
- // Initialize source fields
- mSrcContext = srcContext;
- mSrcHandler = srcHandler;
- mSrcMessenger = new Messenger(mSrcHandler);
- // Initialize destination fields
- mDstMessenger = dstMessenger;
- if (DBG) log("connected srcHandler to the dstMessenger X");
- }
至此可知,我们通过NetworkAgent向CS报告网络的变化,通知它进行网络状态的更新。EthernetNetworkFactory中通过updateAgent()完成此项工作:
这里以NetworkInfo的更新为例:
通过已经建立的AsyncChannel连接向ConnectifyService发送消息,并附带需要更新的NetworkInfo对象,这样CS中NetworkStateTrackerHandler就可以收到消息,并进行网络状态更新了。
- public void updateAgent() {
- synchronized (EthernetNetworkFactory.this) {
- if (mNetworkAgent == null) return;
- if (DBG) {
- Log.i(TAG, "Updating mNetworkAgent with: " +
- mNetworkCapabilities + ", " +
- mNetworkInfo + ", " +
- mLinkProperties);
- }
- mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
- mNetworkAgent.sendNetworkInfo(mNetworkInfo);
- mNetworkAgent.sendLinkProperties(mLinkProperties);
- // never set the network score below 0.
- mNetworkAgent.sendNetworkScore(mLinkUp? NETWORK_SCORE : 0);
- }
- }
- /**
- * Called by the bearer code when it has new NetworkInfo data.
- */
- public void sendNetworkInfo(NetworkInfo networkInfo) {
- queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo));
- }
- private void queueOrSendMessage(int what, Object obj) {
- synchronized (mPreConnectedQueue) {
- if (mAsyncChannel != null) {
- mAsyncChannel.sendMessage(what, obj);//mDstMessenger指向CS中的NetworkStateTrackerHandler,mSrcMessenger指向当前NetworkAgent.
- } else {
- Message msg = Message.obtain();
- msg.what = what;
- msg.obj = obj;
- mPreConnectedQueue.add(msg);
- }
- }
- }