Android13 ConnectivityManager requestNetwork 流程分析

ConnectivityManager的requestNetwork方法是一个用于请求满足特定条件的网络连接的方法。它通常在应用需要特定类型网络的情况下使用,例如需要大量数据传输时可能会请求一个高带宽的网络。当满足NetworkRequest的条件时,requestNetwork会尝试主动去连接到一个满足条件的网络。

通过ConnectivityManager和通过WifiManager连接网络的区别在于使用的API和功能。

通过ConnectivityManager连接网络是一种更通用的方法,它可以用于获取当前活动的网络连接信息,并可以根据需要切换网络连接。通过ConnectivityManager可以获取到网络的状态、类型、连接状态等信息,可以用于判断当前网络是否可用、判断网络类型(如WiFi、移动数据等)、监听网络连接状态的变化等。

而通过WifiManager连接网络则是针对WiFi网络的连接操作。WifiManager提供了一系列的方法,用于扫描可用的WiFi网络、连接指定的WiFi网络、断开当前连接的WiFi网络等。通过WifiManager可以实现WiFi网络的连接和管理,包括连接到指定的WiFi网络、获取当前连接的WiFi网络信息、获取已保存的WiFi网络列表等。

总结起来,通过ConnectivityManager连接网络更加通用,可以用于判断和管理各种类型的网络连接,而通过WifiManager连接网络则是针对WiFi网络的连接和管理

下面分析ConnectivityManager的requestNetwork方法:

//packages/modules/Connectivity/framework/src/android/net/ConnectivityManager.java
public class ConnectivityManager {
    public void requestNetwork(@NonNull NetworkRequest request,
            @NonNull NetworkCallback networkCallback) {
        requestNetwork(request, networkCallback, getDefaultHandler());
    }
}

调用requestNetwork重载方法:

//packages/modules/Connectivity/framework/src/android/net/ConnectivityManager.java
public class ConnectivityManager {
    public void requestNetwork(@NonNull NetworkRequest request,
            @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
        CallbackHandler cbHandler = new CallbackHandler(handler);
        NetworkCapabilities nc = request.networkCapabilities;
        sendRequestForNetwork(nc, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
    }
}

调用sendRequestForNetwork方法:

//packages/modules/Connectivity/framework/src/android/net/ConnectivityManager.java
public class ConnectivityManager {
    private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
            int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
        return sendRequestForNetwork(Process.INVALID_UID, need, callback, timeoutMs, reqType,
                legacyType, handler);
    }
}

调用sendRequestForNetwork重载方法:

//packages/modules/Connectivity/framework/src/android/net/ConnectivityManager.java
public class ConnectivityManager {
    private final IConnectivityManager mService;
    private NetworkRequest sendRequestForNetwork(int asUid, NetworkCapabilities need,
            NetworkCallback callback, int timeoutMs, NetworkRequest.Type reqType, int legacyType,
            CallbackHandler handler) {
        printStackTrace();
        checkCallbackNotNull(callback);
        if (reqType != TRACK_DEFAULT && reqType != TRACK_SYSTEM_DEFAULT && need == null) {
            throw new IllegalArgumentException("null NetworkCapabilities");
        }
        final NetworkRequest request;
        final String callingPackageName = mContext.getOpPackageName();
        try {
            synchronized(sCallbacks) {
                if (callback.networkRequest != null
                        && callback.networkRequest != ALREADY_UNREGISTERED) {
                    // TODO: throw exception instead and enforce 1:1 mapping of callbacks
                    // and requests (http://b/20701525).
                    Log.e(TAG, "NetworkCallback was already registered");
                }
                Messenger messenger = new Messenger(handler);
                Binder binder = new Binder();
                final int callbackFlags = callback.mFlags;
                if (reqType == LISTEN) {
                    request = mService.listenForNetwork(
                            need, messenger, binder, callbackFlags, callingPackageName,
                            getAttributionTag());
                } else {
                    request = mService.requestNetwork(
                            asUid, need, reqType.ordinal(), messenger, timeoutMs, binder,
                            legacyType, callbackFlags, callingPackageName, getAttributionTag());
                }
                if (request != null) {
                    sCallbacks.put(request, callback);
                }
                callback.networkRequest = request;
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } catch (ServiceSpecificException e) {
            throw convertServiceException(e);
        }
        return request;
    }
}

调用IConnectivityManager的listenForNetwork和requestNetwork方法,IConnectivityManager是一个接口,由ConnectivityService实现,因此会调用ConnectivityService的listenForNetwork和requestNetwork方法。

ConnectivityService listenForNetwork 

ConnectivityService的listenForNetwork方法:

//packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished {
    public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities,
            Messenger messenger, IBinder binder,
            @NetworkCallback.Flag int callbackFlags,
            @NonNull String callingPackageName, @NonNull String callingAttributionTag) {
        final int callingUid = mDeps.getCallingUid();
        if (!hasWifiNetworkListenPermission(networkCapabilities)) {
            enforceAccessPermission();
        }


        NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
        ensureSufficientPermissionsForRequest(networkCapabilities,
                Binder.getCallingPid(), callingUid, callingPackageName);
        restrictRequestUidsForCallerAndSetRequestorInfo(nc, callingUid, callingPackageName);
        // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
        // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
        // onLost and onAvailable callbacks when networks move in and out of the background.
        // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE
        // can't request networks.
        restrictBackgroundRequestForCaller(nc);
        ensureListenableCapabilities(nc);


        NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
                NetworkRequest.Type.LISTEN);
        NetworkRequestInfo nri =
                new NetworkRequestInfo(callingUid, networkRequest, messenger, binder, callbackFlags,
                        callingAttributionTag);
        if (VDBG) log("listenForNetwork for " + nri);


        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
        return networkRequest;
    }
}

发送EVENT_REGISTER_NETWORK_LISTENER消息,消息在ConnectivityService的InternalHandler类的handleMessage方法中处理:

//packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished {
    private class InternalHandler extends Handler {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EVENT_REGISTER_NETWORK_REQUEST:
                case EVENT_REGISTER_NETWORK_LISTENER: {
                    handleRegisterNetworkRequest((NetworkRequestInfo) msg.obj);
                    break;
                }
        }
    }
}

handleRegisterNetworkRequest

调用handleRegisterNetworkRequest方法:

//packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished {
    private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) {
        handleRegisterNetworkRequests(Collections.singleton(nri));
    }
}

调用handleRegisterNetworkRequests方法:

//packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished {
    private void handleRegisterNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
        ensureRunningOnConnectivityServiceThread();
        for (final NetworkRequestInfo nri : nris) {
            mNetworkRequestInfoLogs.log("REGISTER " + nri);
            checkNrisConsistency(nri);
            for (final NetworkRequest req : nri.mRequests) {
                mNetworkRequests.put(req, nri);
                // TODO: Consider update signal strength for other types.
                if (req.isListen()) {
                    for (final NetworkAgentInfo network : mNetworkAgentInfos) {
                        if (req.networkCapabilities.hasSignalStrength()
                                && network.satisfiesImmutableCapabilitiesOf(req)) {
                            updateSignalStrengthThresholds(network, "REGISTER", req);
                        }
                    }
                }
            }


            // If this NRI has a satisfier already, it is replacing an older request that
            // has been removed. Track it.
            final NetworkRequest activeRequest = nri.getActiveRequest();
            if (null != activeRequest) {
                // If there is an active request, then for sure there is a satisfier.
                nri.getSatisfier().addRequest(activeRequest);
            }
        }


        if (mFlags.noRematchAllRequestsOnRegister()) {
            rematchNetworksAndRequests(nris);
        } else {
            rematchAllNetworksAndRequests();
        }


        // Requests that have not been matched to a network will not have been sent to the
        // providers, because the old satisfier and the new satisfier are the same (null in this
        // case). Send these requests to the providers.
        for (final NetworkRequestInfo nri : nris) {
            for (final NetworkOfferInfo noi : mNetworkOffers) {
                informOffer(nri, noi.offer, mNetworkRanker);
            }
        }
    }
}

ConnectivityService requestNetwork

ConnectivityService的requestNetwork方法用于请求网络,代码如下:

//packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished {
    public NetworkRequest requestNetwork(int asUid, NetworkCapabilities networkCapabilities,
            int reqTypeInt, Messenger messenger, int timeoutMs, final IBinder binder,
            int legacyType, int callbackFlags, @NonNull String callingPackageName,
            @Nullable String callingAttributionTag) {
        if (legacyType != TYPE_NONE && !checkNetworkStackPermission()) {
            if (isTargetSdkAtleast(Build.VERSION_CODES.M, mDeps.getCallingUid(),
                    callingPackageName)) {
                throw new SecurityException("Insufficient permissions to specify legacy type");
            }
        }
        final NetworkCapabilities defaultNc = mDefaultRequest.mRequests.get(0).networkCapabilities;
        final int callingUid = mDeps.getCallingUid();
        // Privileged callers can track the default network of another UID by passing in a UID.
        if (asUid != Process.INVALID_UID) {
            enforceSettingsPermission();
        } else {
            asUid = callingUid;
        }
        final NetworkRequest.Type reqType;
        try {
            reqType = NetworkRequest.Type.values()[reqTypeInt];
        } catch (ArrayIndexOutOfBoundsException e) {
            throw new IllegalArgumentException("Unsupported request type " + reqTypeInt);
        }
        switch (reqType) {
            case TRACK_DEFAULT:
                // If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities}
                // is unused and will be replaced by ones appropriate for the UID (usually, the
                // calling app). This allows callers to keep track of the default network.
                networkCapabilities = copyDefaultNetworkCapabilitiesForUid(
                        defaultNc, asUid, callingUid, callingPackageName);
                enforceAccessPermission(); //强制执行访问权限
                break;
            case TRACK_SYSTEM_DEFAULT:
                enforceSettingsPermission(); //强制执行设置权限
                networkCapabilities = new NetworkCapabilities(defaultNc);
                break;
            case BACKGROUND_REQUEST:
                enforceNetworkStackOrSettingsPermission(); //强制执行网络堆栈或设置权限
                // Fall-through since other checks are the same with normal requests.
            case REQUEST:
                networkCapabilities = new NetworkCapabilities(networkCapabilities);
                enforceNetworkRequestPermissions(networkCapabilities, callingPackageName,
                        callingAttributionTag, callingUid); //强制执行网络请求权限
                // TODO: this is incorrect. We mark the request as metered or not depending on
                //  the state of the app when the request is filed, but we never change the
                //  request if the app changes network state. http://b/29964605
                enforceMeteredApnPolicy(networkCapabilities); //实施按流量计费的APN策略
                break;
            case LISTEN_FOR_BEST:
                enforceAccessPermission(); //强制执行访问权限
                networkCapabilities = new NetworkCapabilities(networkCapabilities);
                break;
            default:
                throw new IllegalArgumentException("Unsupported request type " + reqType);
        }
        ensureRequestableCapabilities(networkCapabilities); //确保可请求功能
        ensureSufficientPermissionsForRequest(networkCapabilities,
                Binder.getCallingPid(), callingUid, callingPackageName); //确保请求的足够权限


        // Enforce FOREGROUND if the caller does not have permission to use background network.
        if (reqType == LISTEN_FOR_BEST) {
            restrictBackgroundRequestForCaller(networkCapabilities);
        }


        // Set the UID range for this request to the single UID of the requester, unless the
        // requester has the permission to specify other UIDs.
        // This will overwrite any allowed UIDs in the requested capabilities. Though there
        // are no visible methods to set the UIDs, an app could use reflection to try and get
        // networks for other apps so it's essential that the UIDs are overwritten.
        // Also set the requester UID and package name in the request.
        restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
                callingUid, callingPackageName); //将此请求的 UID 范围设置为请求者的单个 UID,除非请求者有权指定其他 UID


        if (timeoutMs < 0) {
            throw new IllegalArgumentException("Bad timeout specified");
        }


        final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                nextNetworkRequestId(), reqType); //创建NetworkRequest对象
        final NetworkRequestInfo nri = getNriToRegister(
                asUid, networkRequest, messenger, binder, callbackFlags,
                callingAttributionTag); //取得NetworkRequestInfo对象
        if (DBG) log("requestNetwork for " + nri);


        // For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
        // copied from the default request above. (This is necessary to ensure, for example, that
        // the callback does not leak sensitive information to unprivileged apps.) Check that the
        // changes don't alter request matching.
        if (reqType == NetworkRequest.Type.TRACK_SYSTEM_DEFAULT &&
                (!networkCapabilities.equalRequestableCapabilities(defaultNc))) {
            throw new IllegalStateException(
                    "TRACK_SYSTEM_DEFAULT capabilities don't match default request: "
                    + networkCapabilities + " vs. " + defaultNc);
        }


        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri)); //发送EVENT_REGISTER_NETWORK_REQUEST消息
        if (timeoutMs > 0) {
            mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
                    nri), timeoutMs); //发送EVENT_TIMEOUT_NETWORK_REQUEST消息
        }
        return networkRequest;
    }
}

发送EVENT_REGISTER_NETWORK_REQUEST和EVENT_TIMEOUT_NETWORK_REQUEST消息,消息在ConnectivityService的InternalHandler类的handleMessage方法中处理:

//packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished {
    private class InternalHandler extends Handler {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EVENT_REGISTER_NETWORK_REQUEST:
                case EVENT_REGISTER_NETWORK_LISTENER: {
                    handleRegisterNetworkRequest((NetworkRequestInfo) msg.obj);
                    break;
                }
                case EVENT_TIMEOUT_NETWORK_REQUEST: {
                    NetworkRequestInfo nri = (NetworkRequestInfo) msg.obj;
                    handleTimedOutNetworkRequest(nri);
                    break;
                }
        }
    }
}

handleRegisterNetworkRequest

调用handleRegisterNetworkRequest方法:

//packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished {
    private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) {
        handleRegisterNetworkRequests(Collections.singleton(nri));
    }
}

调用handleRegisterNetworkRequests方法:

//packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished {
    private void handleRegisterNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
        ensureRunningOnConnectivityServiceThread();
        for (final NetworkRequestInfo nri : nris) {
            mNetworkRequestInfoLogs.log("REGISTER " + nri);
            checkNrisConsistency(nri);
            for (final NetworkRequest req : nri.mRequests) {
                mNetworkRequests.put(req, nri);
                // TODO: Consider update signal strength for other types.
                if (req.isListen()) {
                    for (final NetworkAgentInfo network : mNetworkAgentInfos) {
                        if (req.networkCapabilities.hasSignalStrength()
                                && network.satisfiesImmutableCapabilitiesOf(req)) {
                            updateSignalStrengthThresholds(network, "REGISTER", req);
                        }
                    }
                }
            }


            // If this NRI has a satisfier already, it is replacing an older request that
            // has been removed. Track it.
            final NetworkRequest activeRequest = nri.getActiveRequest();
            if (null != activeRequest) {
                // If there is an active request, then for sure there is a satisfier.
                nri.getSatisfier().addRequest(activeRequest);
            }
        }


        if (mFlags.noRematchAllRequestsOnRegister()) {
            rematchNetworksAndRequests(nris);
        } else {
            rematchAllNetworksAndRequests();
        }


        // Requests that have not been matched to a network will not have been sent to the
        // providers, because the old satisfier and the new satisfier are the same (null in this
        // case). Send these requests to the providers.
        for (final NetworkRequestInfo nri : nris) {
            for (final NetworkOfferInfo noi : mNetworkOffers) {
                informOffer(nri, noi.offer, mNetworkRanker);
            }
        }
    }
}

handleTimedOutNetworkRequest

调用handleTimedOutNetworkRequest方法:

//packages/modules/Connectivity/service/src/com/android/server/ConnectivityService.java
public class ConnectivityService extends IConnectivityManager.Stub implements PendingIntent.OnFinished {
    private void handleTimedOutNetworkRequest(@NonNull final NetworkRequestInfo nri) {
        ensureRunningOnConnectivityServiceThread();
        // handleTimedOutNetworkRequest() is part of the requestNetwork() flow which works off of a
        // single NetworkRequest and thus does not apply to multilayer requests.
        ensureNotMultilayerRequest(nri, "handleTimedOutNetworkRequest");
        if (mNetworkRequests.get(nri.mRequests.get(0)) == null) {
            return;
        }
        if (nri.isBeingSatisfied()) {
            return;
        }
        if (VDBG || (DBG && nri.mRequests.get(0).isRequest())) {
            log("releasing " + nri.mRequests.get(0) + " (timeout)");
        }
        handleRemoveNetworkRequest(nri);
        callCallbackForRequest(
                nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
    }
}
  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值