Android -- 网络模块中NetworkFactory与NetworkAgent的通信机制
来源:互联网 发布:淘宝为啥不卖斐讯 编辑:程序博客网 时间:2024/06/05 05:31
Android -- NetworkFactory与NetworkAgent的通信机制
在上一篇博文中讲到,EthernetNetworkFactory包揽了Ethernet所有的网络管理操作,这其中就包含怎么样通知ConnectifyService(下文都简称CS)网络状态发生变化。接下来,我们借助有线网络来简要介绍Android 4.4之后,网络模块是怎样与CS通信并进行网络管理的。
在启动Ethernet网络服务时,我们会对Ethernet做一些初始化操作,以方便我们进行网络管理。看EthernetNetworkFactory::start()方法:
/** * 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); } }start()方法接受一个Handler对象作为参数,该参数是在EthernetServiceImpl::start()中传入的,它新建了一个HandlerThread对象,并传入作为参数,从这可知网络管理的操作是运行在EthernetServiceImpl线程中的。
代码中创建了一个LocalNetworkFactory对象。LocalNetworkFactory继承自NetworkFactory:
/** * 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() { }...}NetworkFactory继承自Handler,我们可以把它动作一个工厂,对网络的请求和终止操作都通过该对象进行处理。从注释可知NetworkFactory与NetworkAgent对象有密切关系,它通过register()方法向CS进行注册。start/stopNetwork()是提供的回调函数 ,我们可以通过这两个函数来请求或终止网络:
public void register() { if (DBG) log("Registering NetworkFactory"); if (mMessenger == null) { mMessenger = new Messenger(this); ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG); } }创建NetworkFactory对象时,我们给它指定了一个特定线程的Looper对象;接着调用register()方法向CS注册这个NetworkFactory对象,实际是调用CS中的registerNetworkFactory()方法:
@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)); }参数Messenger对象是一个可以跨进程传递的实例对象,它实际代表一个Handler对象,我们可以像使用Handler对象一样,使用Messenger对象来发送消息;此处该引用指向mNetworkFactory这个Handler对象,它绑定的Looper属于一个特定的线程,它在EthernetServiceImpl中创建。看NetworkFactoryInfo,它是一个CS中的内部类,保存了特定的Messager对象和一个与之关联的AsyncChannel对象。看到此处我们知道这里会通过异步通道来进行消息传递的。接着会发送一个EVENT_REGISTER_NETWORK_FACTORY消息,它被CS中的InternalHandler处理,这个Handler主要完成CS内部消息事件的处理。我们直接看处理过程:
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); }异步通道的内容在以前的博文中已经讲过。先将之前创建的nfi对象以Messenger对象为key添加到mNetworkFactoryInfos中,它是一个HashMap对象,方便后面获取。再调用connect()方法进行AsyncChannel连接的创建:
/** * 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); }CS中是这样处理的:
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); } } } }我们先前已经向mNetworkFactoryInfos集合添加过NetworkFactoryInfo对象,实际的处理是:
// 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); }直接看消息发送处理;通过AsyncChannel对象向mDstMessenger对象发送消息。根据前面所述,即向Ethernet中的LocalNetworkFactory发送CMD_REQUEST_NETWORK消息,表示当前系统要请求一个网络。有前面可知父类NetworkFactory本身就是一个Handler,它处理该消息:
@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"); } }如果消息附带的NetworkRequestInfo对象没有保存,则先保存到mNetworkRequests集合中,同时根据NetworkRequestInfo对象中的requested和score属性值,相应的调用needNetworkFor()或releaseNetworkFor():
// 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(); }即调用LocalNetworkFactory中的start/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()处理Ethernet的连接操作,包括对静态IP和DHCP的处理。到这里,一个NetworkFactory对象的注册过程就结束了。
我们看onRequestNetwork()方法来触发一个网络的连接:
/* 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(); }CS中处理网络更新的Handler是NetworkStateTrackerHandler。当网络连接后,通知CS更新网络的操作则是通过NetworkAgent对象进行的。从它的定义可知,它也是一个Handler:
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();重写的unwanted()方法则在CS指出不再需要当前网络连接时调用。除了清除掉网络配置信息,还会把mNetworkAgent置为null。从代码中可以看出,mNetworkAgent是否为null标志了当前是否该类型的网络连接正在使用,如果有则不会处理新的网络请求。
既然网络状态的变化是由NetworkAgent处理的,那我们就接着看NetworkAgent是怎么跟CS通信的:
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); }在创建NetworkAgent对象时,接受一个特定的Looper对象,并向CS注册该NetworkAgent对象,这与LocalNetworkFactory的处理类似。看CS中具体的注册处理:
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; }这里的Messager对象是NetworkAgent对象自身的一个引用,创建对应的NetworkAgentInfo对象,其内部创建了一个AsyncChannel对象;messenger参数前面介绍过,mTrackderHandler是NetworkStateTrackerHandler的一个实例。向InternalHandler发送EVENT_REGISTER_NETWORK_AGENT消息,处理注册操作。看CS中的处理:
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);//更新网络状态的函数 }也是将na和messenger对象保存到一个HashMap集合中,也是通过AsyncChannel进行通信,也是调用connect()进行连接,这跟前面所述的NetworkFactory的处理基本类似。从前面的分析可知这个AsyncChannel对象中,mSrcHandler和mSrcMessenger指向一个CS中的NetworkStateTrackerHandler,mDstMessenger指向要注册的NetworkAgent对象,因为它本身也是个Handler。接着向mSrcHandler发送CMD_CHANNEL_HALF_CONNECTED消息,同样也是handleAsyncChannelHalfConnect()处理,只不过走的处理分支不同,有前面的介绍可知:
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);使用AsyncChannel向mDstMessenger发送CMD_CHANNEL_FULL_CONNECTION消息,即向NetworkAgent对象发送该消息:
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是第一次进行连接,mAsyncChannel为null;新建一个AsyncChannel对象,调用connected()进行FULL_CONNECTION:
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"); }mSrcHandler和mSrcMessenger指向当前的NetworkAgent对象;mDstMessenger指向CS中的NetworkStateTrackerHandler对象。随后再发送CMD_CHANNEL_FULLY_CONNECTED消息,表示整个AsyncChannel的连接成功,可以进行通信了。同时,还会遍历mPreConnectedQueue集合,这个集合中保存了当mAsyncChannel为null时的所有与更新网络信息相关的message,通过ac.sendMessage()向CS发送所有的message进行状态更新(要注意,ac对象的mSrcHanlder为当前NetworkAgent,mDstMessenger指向NetworkStateTrackerHandler)。
至此可知,我们通过NetworkAgent向CS报告网络的变化,通知它进行网络状态的更新。EthernetNetworkFactory中通过updateAgent()完成此项工作:
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); } }这里以NetworkInfo的更新为例:
/** * 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); } } }通过已经建立的AsyncChannel连接向ConnectifyService发送消息,并附带需要更新的NetworkInfo对象,这样CS中NetworkStateTrackerHandler就可以收到消息,并进行网络状态更新了。
0 0
- Android -- 网络模块中NetworkFactory与NetworkAgent的通信机制
- Android -- 网络模块中NetworkFactory与NetworkAgent的通信机制
- Android -- Ethernet网络模块中NetworkFactory与NetworkAgent的通信机制
- 网络连接评分机制之NetworkAgent
- 网络连接评分机制之NetworkAgent
- 网络连接评分机制之NetworkAgent
- 网络连接评分机制之NetworkFactory
- 网络连接评分机制之NetworkFactory
- 网络连接评分机制之NetworkFactory
- 网络连接评分机制之NetworkFactory
- Android的通信机制与网络(一)
- Android的通信机制与网络(二)
- Android的通信机制与网络(三)
- (转载)Android的通信机制与网络(…
- Android的通信机制与网络(一)
- Android的通信机制与网络(二)
- Android的通信机制与网络(三)
- 网络连接评分机制之NetworkAgent(原)
- post插件
- 二叉树的三种遍历方式java实现
- GMT与UTC区别
- android 第三方库名字、作用、文章
- 阿里云window环境安装oracle数据库 报错的问题
- Android -- 网络模块中NetworkFactory与NetworkAgent的通信机制
- Struts2文件上传
- memchr
- NOIP2015 运输计划 树链剖分 差分 二分
- 测试常见问题
- AIDL实战简述
- CSP考试 2015年12月第3题 画图 C++实现
- python的注释
- 剑指offer(六十五)之矩阵中的路径