Android 9.0 网络评分之---NetworkFactory

Posted Mrsongs的心情杂货铺

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 9.0 网络评分之---NetworkFactory相关的知识,希望对你有一定的参考价值。

一、网络评分框架图

二、NetworkFactory 与ConnectivityService连接过程

拿以太网为例,以太网的网口检测类EthernetTracker 会在自己的构造函数中将以太网类型的networkfactory 注册到ConnectivityService中。

EthernetTracker(Context context, Handler handler) 
    mHandler = handler;

    // The services we use.
    IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
    mNMService = INetworkManagementService.Stub.asInterface(b);

    // Interface match regex.
    mIfaceMatch = context.getResources().getString(
            com.android.internal.R.string.config_ethernet_iface_regex);

    // Read default Ethernet interface configuration from resources
    final String[] interfaceConfigs = context.getResources().getStringArray(
            com.android.internal.R.array.config_ethernet_interfaces);
    for (String strConfig : interfaceConfigs) 
        parseEthernetConfig(strConfig);
    

    mConfigStore = new EthernetConfigStore();

    NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */);
    mFactory = new EthernetNetworkFactory(handler, context, nc);
    mFactory.register();

NetworkFactory 中会的register 方法如下:
public void register()
if (DBG) log(“Registering NetworkFactory”);
if (mMessenger == null)
mMessenger = new Messenger(this);
ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG);

ConnectivityService 中的registerNetworkFactory 方法。会为当前NetworkFactory创建一个NetworkFactoryInfo ,并通过mHandler 发送EVENT_REGISTER_NETWORK_FACTORY

从这里我们看到,在ConnectivityService中,利用当前的NetworkFactory创建NetworkFactoryInfo对象,该对象保存了当前网络连接的name、Messenger对象,并且为其创建了AsyncChannel。 接下来继续看注册过程:
@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));

NetworkFactoryInfo是ConnectivityService 的一个内部类,会保存当前的NetworkFactory 的messenger和asyncChannel 对象,这里name 就是EthernetNetworkFactory 里面定义的类型NETWORK_TYPE = “Ethernet”
private static class NetworkFactoryInfo
public final String name;
public final Messenger messenger;
public final AsyncChannel asyncChannel;

    public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel) 
        this.name = name;
        this.messenger = messenger;
        this.asyncChannel = asyncChannel;
    

mHandler 是ConnectivityService 的一个内部类 InternalHandler
private class InternalHandler extends Handler
public InternalHandler(Looper looper)
super(looper);

    @Override
    public void handleMessage(Message msg) 
        switch (msg.what) 
            case EVENT_REGISTER_NETWORK_FACTORY: 
                handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj);
                break;
            

到这里我们发现,ConnectivityService将当前的NetworkFactoryInfo保存到mNetworkFactoryInfos中,然后向当前的NetworkFactory发起AsyncChannel单向通道申请(AsyncChannel相关介绍见这里)。
申请成功时,将会向当前的mTrackerHandler发送CMD_CHANNEL_HALF_CONNECTED消息:
原文链接:https://blog.csdn.net/u010961631/article/details/48971431
这里面是通过AsyncChannel 让ConnectivityService 的mTrackerHandler 和NetworkFactory连接通信。
三、ConnectivityService 通过AsyncChannel与NetworkFactory 连接的详细过程
AsyncChannel 的客户端(ConnectivityService)发起connect请求,和NetworkFactory连接。所以AsyncChannel 就架起了客户端ConnectivityService 的mTrackerHandler与服务端NetworkFactory之间的桥梁。连接成功后,ConnectivityService会收到AsyncChannel.CMD_CHANNEL_HALF_CONNECTED 的message。当客户端接收到AsyncChannel.CMD_CHANNEL_HALF_CONNECTED消息后,说明当前的单项通道建立成功。此时的客户端可以通过sAsyncChannel的sendMessage()方法向服务端发送消息了。
原文链接:https://blog.csdn.net/u010961631/article/details/48179305
AsyncChannel 的例子:https://blog.csdn.net/u010961631/article/details/48179305

作为客户端,如果想要创建与服务端之间的AsyncChannel,需要做以下几个准备:
1、获取服务端的Messenger对象,该对象其实就是利用服务端的Handler构建的Messenger;
2、创建客户端自己的Handler对象;
3、创建AsyncChannel对象;
4、通过AsyncChannel对象,连接当前的Handler和服务端的Messenger,从而申请连接。

3.1 首先ConnectvityService 发起connect 连接 NetworkFactory
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);

3.2 连接成功后客户端ConnectivityService会收到服务端NetworkFactory发来的AsyncChannel.CMD_CHANNEL_HALF_CONNECTED

AsyncChannel的connected 方法实际上连接的是传入的客户端handler 和服务端messager。
代码路径:frameworks/base/core/java/com/android/internal/util/AsyncChannel.java

3.3 connect 方法如下,这里会执行connected()replyHalfConnected(STATUS_SUCCESSFUL)
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");

    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");

3.4 AsyncChannnel 的 replyHalfConnected 主要回复CMD_CHANNEL_HALF_CONNECTED MSG和添加msg.arg1为STATUS_SUCCESSFUL的参数
private void replyHalfConnected(int status)
Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
msg.arg1 = status;
msg.obj = this;
msg.replyTo = mDstMessenger;
if (!linkToDeathMonitor())
// Override status to indicate failure
msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;

    mSrcHandler.sendMessage(msg);

3.5 单向通道建立,ConnectivityService 收到AsyncChannel.STATUS_SUCCESSFUL 后发送网络请求android.net.NetworkFactory.CMD_REQUEST_NETWORK
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.request.isListen()) continue;
NetworkAgentInfo nai = getNetworkForRequest(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);



3.5 NetworkFactory 收到CMD_REQUEST_NETWORK请求。
@Override
public void handleMessage(Message msg)
switch (msg.what)
case CMD_REQUEST_NETWORK:
handleAddRequest((NetworkRequest)msg.obj, msg.arg1);
break;

3.6 handleAddRequest创建一个NetworkRequestInfo 对象将请求的ID保存起来并保存分数。
@VisibleForTesting
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
if (VDBG) log(“new score " + score + " for exisiting request " + request);
n.score = score;

if (VDBG) log(” my score=” + mScore + “, my filter=” + mCapabilityFilter);

    evalRequest(n);

3.7 然后评价该网络的分数是否可以用于上网
private void evalRequest(NetworkRequestInfo n)
if (VDBG) log(“evalRequest”);
// we always NEED each network for any network request
//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没有被requested过,并且其分值(n.score)小于当前NetworkFactory自己的分值(mScore),那么就说明,当前NetworkFactory所处的网络优先级高于其他网络的优先级,就会触发当前NetworkFactory所在网络的needNetworkFor()流程,也就是连接建立流程,并将标记NetworkRequestInfo.requested=true。
当NetworkRequestInfo被requested过(也就是当前网络被needNetworkFor过),此时如果再次收到请求,并且携带的新score大于当前NetworkFactory所处网络的mScore,那么就说明当前NetworkFactory所在网络优先级已经不是最高,需要将其releaseNetworkFor掉,并标记NetworkRequestInfo.requested=false。
对于初始化流程来说,由于NetworkRequestInfo是刚才在handleAddRequest新创建的,所以其requested状态必然为false,而且我们前面提到,ConnectivityService发送CMD_REQUEST_NETWORK时携带的分值参数为0,并且对于数据网络来说,其mScore=50,因此此时的判定状态将会是:n.requested=false AND n.score < mScore。
也就是说,对于数据网络环境初始化过程来说,将会满足第一个if判断,进入needNetworkFor流程,也就是触发数据网络的建立。
至此,NetworkFactory注册流程结束。

四、ConnectivityService 的mTrackerHandler
mTrackerHandler是ConnectivityService定义的一个内部类Handler。里面主要处理maybeHandleAsyncChannelMessage(NetworkFactory), NetworkMonitor, NetworkAgentInfo和NetworkAgent 的消息。

    @Override
    public void handleMessage(Message msg) 
        if (!maybeHandleAsyncChannelMessage(msg) &&
                !maybeHandleNetworkMonitorMessage(msg) &&
                !maybeHandleNetworkAgentInfoMessage(msg)) 
            maybeHandleNetworkAgentMessage(msg);
        
    


// must be stateless - things change under us.
private class NetworkStateTrackerHandler extends Handler 
    public NetworkStateTrackerHandler(Looper looper) 
        super(looper);
    

    private boolean maybeHandleAsyncChannelMessage(Message msg) 
        switch (msg.what) 
            default:
                return false;
            case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 
                handleAsyncChannelHalfConnect(msg);
                break;
            
            case AsyncChannel.CMD_CHANNEL_DISCONNECT: 
                NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
                if (nai != null) nai.asyncChannel.disconnect();
                break;
            
            case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 
                handleAsyncChannelDisconnected(msg);
                break;
            
        
        return true;
    

    private void maybeHandleNetworkAgentMessage(Message msg) 
        NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
        if (nai == null) 
            if (VDBG) 
                log(String.format("%s from unknown NetworkAgent", eventName(msg.what)));
            
            return;
        

        switch (msg.what) 
            case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: 
                final NetworkCapabilities networkCapabilities = (NetworkCapabilities) msg.obj;
                if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) ||
                        networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED) ||
                        networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) 
                    Slog.wtf(TAG, "BUG: " + nai + " has CS-managed capability.");
                
                updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
                break;
            
            case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: 
                handleUpdateLinkProperties(nai, (LinkProperties) msg.obj);
                break;
            
            case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: 
                NetworkInfo info = (NetworkInfo) msg.obj;
                updateNetworkInfo(nai, info);
                break;
            
            case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: 
                Integer score = (Integer) msg.obj;
                if (score != null) updateNetworkScore(nai, score.intValue());
                break;
            
            case NetworkAgent.EVENT_SET_EXPLICITLY_SELECTED: 
                if (nai.everConnected && !nai.networkMisc.explicitlySelected) 
                    loge("ERROR: already-connected network explicitly selected.");
                
                nai.networkMisc.explicitlySelected = true;
                nai.networkMisc.acceptUnvalidated = (boolean) msg.obj;
                break;
            
            case NetworkAgent.EVENT_PACKET_KEEPALIVE: 
                mKeepaliveTracker.handleEventPacketKeepalive(nai, msg);
                break;
            
        
    

    private boolean maybeHandleNetworkMonitorMessage(Message msg) 
        switch (msg.what) 
            default:
                return false;
            case NetworkMonitor.EVENT_NETWORK_TESTED: 
                final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
                if (nai == null) break;

                final boolean valid = (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
                final boolean wasValidated = nai.lastValidated;
                final boolean wasDefault = isDefaultNetwork(nai);

                final String redirectUrl = (msg.obj instanceof String) ? (String) msg.obj : "";

                if (DBG) 
                    final String logMsg = !TextUtils.isEmpty(redirectUrl)
                             ? " with redirect to " + redirectUrl
                             : "";
                    log(nai.name() + " validation " + (valid ? "passed" : "failed") + logMsg);
                
                if (valid != nai.lastValidated) 
                    if (wasDefault) 
                        metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
                                SystemClock.elapsedRealtime(), valid);
                    
                    final int oldScore = nai.getCurrentScore();
                    nai.lastValidated = valid;
                    nai.everValidated |= valid;
                    updateCapabilities(oldScore, nai, nai.networkCapabilities);
                    // If score has changed, rebroadcast to NetworkFactories. b/17726566
                    if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
                    if (valid) handleFreshlyValidatedNetwork(nai);
                
                updateInetCondition(nai);
                // Let the NetworkAgent know the state of its network
                Bundle redirectUrlBundle = new Bundle();
                redirectUrlBundle.putString(NetworkAgent.REDIRECT_URL_KEY, redirectUrl);
                nai.asyncChannel.sendMessage(
                        NetworkAgent.CMD_REPORT_NETWORK_STATUS,
                        (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
                        0, redirectUrlBundle);
                if (wasValidated && !nai.lastValidated) 
					nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null);
                    handleNetworkUnvalidated(nai);
                 else if(!wasValidated && nai.lastValidated) 
					nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
					handleNetworkValidated(nai);
                 else if(!wasValidated && !nai.lastValidated) 
                    if(!nai.everFirstUnvalidated) 
                        log(nai.name() + " ever FRIST Unvalidated and notify SUSPENDED.");
                        nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, null, null);
                        handleNetworkUnvalidated(nai);
                        nai.everFirstUnvalidated = true;
                    
                
                break;
            
            case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: 
                final int netId = msg.arg2;
                final boolean visible = toBool(msg.arg1);
                final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(netId);
                // If captive portal status has changed, update capabilities or disconnect.
                if (nai != null && (visible != nai.lastCaptivePortalDetected)) 
                    final int oldScore = nai.getCurrentScore();
                    nai.lastCaptivePortalDetected = visible;
                    nai.everCaptivePortalDetected |= visible;
                    if (nai.lastCaptivePortalDetected &&
                        Settings.Global.CAPTIVE_PORTAL_MODE_AVOID == getCaptivePortalMode()) 
                        if (DBG) log("Avoiding captive portal network: " + nai.name());
                        nai.asyncChannel.sendMessage(
                                NetworkAgent.CMD_PREVENT_AUTOMATIC_RECONNECT);
                        teardownUnneededNetwork(nai);
                        break;
                    
                    updateCapabilities(oldScore, nai, nai.networkCapabilities);
                
                if (!visible) 
                    mNotifier.clearNotification(netId);
                 else 
                    if (nai == null) 
                        loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
                        break;
                    
                    if (!nai.networkMisc.provisioningNotificationDisabled) 
                        mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai, null,
                                (PendingIntent) msg.obj, nai.networkMisc.explicitlySelected);
                    
                
                break;
            
            case NetworkMonitor.EVENT_PRIVATE_DNS_CONFIG_RESOLVED: 
                final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
                if (nai == null) break;

                updatePrivateDns(nai, (PrivateDnsConfig) msg.obj);
                break;
            
        
        return true;
    

    private int getCaptivePortalMode() 
        return Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.CAPTIVE_PORTAL_MODE,
                Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
    

    private boolean maybeHandleNetworkAgentInfoMessage(Message msg) 
        switch (msg.what) 
            default:
                return false;
            case NetworkAgentInfo.EVENT_NETWORK_LINGER_COMPLETE: 
                NetworkAgentInfo nai = (NetworkAgentInfo) msg.obj;
                if (nai != null && isLiveNetworkAgent(nai, msg.what)) 
                    handleLingerComplete(nai);
                
                break;
            
        
        return true;
    

    @Override
    public void handleMessage(Message msg) 
        if (!maybeHandleAsyncChannelMessage(msg) &&
                !maybeHandleNetworkMonitorMessage(msg) &&
                !maybeHandleNetworkAgentInfoMessage(msg)) 
            maybeHandleNetworkAgentMessage(msg);
        
    

博客链接:https://blog.csdn.net/u010961631/article/details/48971431

以上是关于Android 9.0 网络评分之---NetworkFactory的主要内容,如果未能解决你的问题,请参考以下文章

Android 9.0 网络评分之---NetworkFactory

Android 9.0 网络评分之--NetworkAgent

Android 9.0 网络评分之--NetworkAgent

Android 9.0 网络评分之--NetworkAgent

Android9.0 网络评分之--NetworkMonitor

Android9.0 网络评分之--NetworkMonitor